JSONResponseView显示空对象求助:已接收有效JSON却无法展示
问题原因与解决方案
问题原因
后台线程更新UI状态
URLSession的dataTask闭包运行在后台线程,你直接在闭包里更新responseJSON和showingResponseView这些SwiftUI状态属性,而SwiftUI要求所有状态更新必须在主线程执行。虽然控制台能打印出正确数据,但状态更新没有同步到UI线程,导致Sheet拿到的还是旧的空数据。Sheet预渲染导致数据不同步
使用sheet(isPresented:)时,Sheet的内容视图(JSONResponseView)会在showingResponseView变为true之前就被预初始化,此时responseJSON还是初始的空值。即使之后更新了responseJSON,由于Sheet已经完成初始化,不会自动响应参数变化,所以展示的还是空对象。
正确实现方式
步骤1:确保状态更新在主线程
在dataTask闭包中,所有更新UI状态的操作必须通过DispatchQueue.main.async切换到主线程执行。
步骤2:使用sheet(item:)替代sheet(isPresented:)
通过sheet(item:)绑定一个可选的响应数据对象,当这个对象有值时自动弹出Sheet,并且每次对象更新时,Sheet会重新初始化视图,确保拿到最新的数据。
修改后的代码示例
首先定义一个遵循Identifiable的响应类型(sheet(item:)要求绑定对象必须实现该协议):
struct JSONResponse: Identifiable { let id = UUID() let data: [String: Any] }
修改原视图的状态属性:
// 替换原来的responseJSON和showingResponseView @State private var response: JSONResponse?
更新sendRequest方法:
func sendRequest(with jsonData: Data) { guard let url = URL(string: "http://localhost:7071/api") else { print("Invalid URL") return } var request = URLRequest(url: url) request.httpMethod = "POST" request.httpBody = jsonData let task = URLSession.shared.dataTask(with: request) { data, response, error in if let error = error { print("Error:", error) return } guard let data = data else { print("No data received") return } if let jsonString = String(data: data, encoding: .utf8) { print("-->Raw JSON Data Received:", jsonString) } do { let result = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] ?? ["Test": "OK"] print(" Report:", result) // 切换到主线程更新状态 DispatchQueue.main.async { self.response = JSONResponse(data: result) } } catch { print("Error parsing JSON:", error) } } task.resume() if let jsonString = String(data: jsonData, encoding: .utf8) { print("Generated JSON Payload Outgoing:\n", jsonString) } }
修改Sheet的调用逻辑:
var body: some View { Form { PersonDetailsSection(name: $person1Name, title: "Enter Person 1's Details") Button { if let jsonData = JSONPayloadGenerator.createPayload(person1Name: person1Name) { sendRequest(with: jsonData) } } label: { Text("Send Request") } } .navigationBarTitle("My App") .padding() // 使用sheet(item:)绑定响应数据,自动触发视图展示 .sheet(item: $response) { response in JSONResponseView(jsonResponse: response.data) .onAppear { print("Presenting JSONResponseView") } } }
内容的提问来源于stack exchange,提问作者Vampavi
相关产品推荐
相关产品推荐

