You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI通过TextField输入值传递给ObservedObject时初始化顺序错误如何解决

问题核心原因

SwiftUI 视图属性的默认初始化执行时机早于实例自身的可用时机,你在定义fetch属性时直接调用未完成初始化的username赋值,因此触发顺序错误。同时你错误将ReallyDetailedView的username声明为@Binding类型,但上层传参是普通值,存在类型不匹配问题。

修复方案

import SwiftUI
//import URLImage

struct Result: Codable{
    var items: [User]
}

struct User: Codable{
    public var login: String
    public var url: String
    public var avatar_url: String
    public var html_url: String
}


struct ContentView: View {
    @State var username: String = ""
    
    var body: some View {
        NavigationView {
            NavigationLink(destination: DetailView(username: $username)) {
                Form {
                    Section {
                        Text("Show detail")
                    }
                    Section {
                        TextField("Enter your username", text: $username)
                        Text("Your username is \(username)")
                    }
                }
            }
        }
    }
}

struct DetailView: View {
    @Binding var username: String
    
    var body: some View {
        VStack(alignment: .leading) {
            Form {
                Section {
                    Text("Username is:\(username)")
                }
                // 移除不必要的Button嵌套,NavigationLink本身可点击
                NavigationLink(destination: ReallyDetailedView(username: username)) {
                    Text("Get Data")
                }
                .foregroundColor(Color.gray)
            }
        }
    }
}

class FetchUsers: ObservableObject {
    @Published var items = [User]()
    var name: String = ""
    init(name: String) {
        self.name = name
        guard let url = URL(string: "https://api.github.com/search/users?q=\(name.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? "")") else {
            print("无效URL")
            return
        }
        URLSession.shared.dataTask(with: url) {(data, response, error) in
            do {
                if let data = data {
                    let decodedData = try JSONDecoder().decode(Result.self, from: data)
                    DispatchQueue.main.async {
                        self.items = decodedData.items
                    }
                } else {
                    print("No data")
                }
            } catch {
                print("Error: \(error.localizedDescription)")
            }
        }.resume()
    }
}


struct ReallyDetailedView: View {
    // 改为普通常量,不需要双向绑定
    let username: String
    // iOS14+推荐用@StateObject作为ObservedObject的持有者,避免重绘释放
    @StateObject var fetch: FetchUsers
    
    // 自定义初始化方法,此时参数username已传入,可用于初始化fetch
    init(username: String) {
        self.username = username
        self._fetch = StateObject(wrappedValue: FetchUsers(name: username))
        // 如果要兼容iOS13用@ObservedObject的话,写法如下:
        // self._fetch = ObservedObject(wrappedValue: FetchUsers(name: username))
    }
    
    var body: some View {
        VStack(alignment: .leading) {
            Text("Username is:\(username)")
            // 放开注释即可展示列表,引入URLImage后可正常显示头像
            List(fetch.items, id: \.login) { user in
                Link(destination: URL(string: user.html_url)!){
                    HStack(alignment: .top){
                        // URLImage(URL(string:user.avatar_url)!){ image in
                        //    image.resizable().frame(width: 50, height: 50)
                        // }
                        Text(user.login)
                    }
                }
            }
        }
    }
}

额外优化点

  • 给搜索关键词加了URL编码,避免特殊字符导致请求失败
  • 移除了无效的冗余变量和嵌套控件
  • 用更安全的可选绑定处理URL生成逻辑

内容的提问来源于stack exchange,提问作者boristheslug

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 11:36:02