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
相关产品推荐
相关产品推荐

