SwiftUI通用视图FetchUrlContentView闭包内数据处理与loading控制问题
解决方案
核心思路是把加载状态、错误状态的管理封装在通用视图内部,外部只需专注数据解析和内容展示,不用手动控制loading状态——通用视图会自动在请求开始时开启加载,请求结束(成功/失败)时关闭加载。
重构通用视图 FetchUrlContentView
import SwiftUI struct FetchUrlContentView<Content: View, DataModel>: View { let url: URL let parseData: (Data) throws -> DataModel // 数据解析闭包 @ViewBuilder let content: (DataModel) -> Content // 内容展示闭包 // 内部管理状态,外部无需操作 @State private var isLoading = false @State private var error: Error? @State private var parsedData: DataModel? var body: some View { Group { if isLoading { ProgressView("加载中...") } else if let error = error { Text("加载失败:\(error.localizedDescription)") .foregroundColor(.red) } else if let data = parsedData { content(data) } else { Color.clear.onAppear(perform: fetchData) } } } private func fetchData() { isLoading = true error = nil URLSession.shared.dataTask(with: url) { data, _, taskError in DispatchQueue.main.async { isLoading = false // 请求结束后统一关闭加载状态 if let taskError = taskError { error = taskError return } guard let data = data else { error = NSError(domain: "FetchError", code: -1, userInfo: [NSLocalizedDescriptionKey: "无返回数据"]) return } do { parsedData = try parseData(data) } catch { self.error = error } } }.resume() } }
复用示例(解析数组并传入 MyView)
// 示例数据模型 struct Item: Codable { let id: Int let name: String } // 自定义展示视图 struct MyView: View { let items: [Item] var body: some View { List(items) { item in Text(item.name) } } } // 实际使用通用视图的场景 struct UsageExample: View { let targetUrl = URL(string: "https://example.com/api/items")! var body: some View { FetchUrlContentView( url: targetUrl, parseData: { data in // 在这里完成数据解析(比如转成数组) try JSONDecoder().decode([Item].self, from: data) }, content: { parsedItems in // 把解析后的数据传入MyView展示 MyView(items: parsedItems) } ) } }
关键说明
- 所有状态(loading、错误、解析后的数据)都由通用视图内部维护,外部无需手动修改
isLoading - 请求流程自动触发:视图出现时发起请求,开始加载→请求完成后关闭加载→解析数据成功则展示内容,失败则展示错误信息
- 外部只需提供三个核心部分:请求URL、数据解析逻辑、内容展示逻辑
内容的提问来源于stack exchange,提问作者chitgoks
相关产品推荐
相关产品推荐

