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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 04:21:00