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

Swift UI API数据加载前初始化UI问题:主线程报错与数据为空

问题解决方案

核心问题修复

1. 将UI操作移至主线程

网络请求的dataTask回调运行在后台线程,直接在里面操作UI会触发线程错误,必须把所有UI相关逻辑包裹在主线程执行。

修改setupUI中的getGenres回调:

getGenres { [weak self] array in
    guard let self = self else { return }
    DispatchQueue.main.async {
        // 隐藏加载提示标签
        self.label.isHidden = true
        // 直接传递数据给ContentView,避免依赖全局变量
        let childView = UIHostingController(rootView: ContentView(competitionsGroup: array))
        self.addChild(childView)
        childView.view.translatesAutoresizingMaskIntoConstraints = false
        self.view.addSubview(childView.view)
        // 使用AutoLayout约束替代frame布局,适配不同屏幕
        NSLayoutConstraint.activate([
            childView.view.topAnchor.constraint(equalTo: self.view.topAnchor),
            childView.view.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
            childView.view.trailingAnchor.constraint(equalTo: self.view.trailingAnchor),
            childView.view.bottomAnchor.constraint(equalTo: self.view.bottomAnchor)
        ])
        childView.didMove(toParent: self)
    }
}

2. 重构ContentView,移除全局依赖并处理空状态

原ContentView依赖全局变量且强制解包,数据未加载完成时会直接崩溃。改为通过初始化参数接收数据,并处理加载中、空数据等状态,避免强制解包。

修改后的ContentView:

struct ContentView: View {
    let competitionsGroup: CompetitionGroup?
    
    var body: some View {
        NavigationView {
            Group {
                // 安全校验数据是否存在且非空
                if let group = competitionsGroup {
                    if !group.competitions.isEmpty {
                        List(group.competitions, id: \.id) { competition in
                            NavigationLink(destination: Text(competition.genericname ?? "未知联赛")) {
                                Image(systemName: "airplane")
                                Text(competition.genericname ?? "未知联赛")
                            }
                            .padding()
                        }
                    } else {
                        Text("暂无联赛数据")
                            .foregroundColor(.secondary)
                    }
                } else {
                    // 数据未加载完成时显示加载状态
                    VStack(spacing: 12) {
                        ProgressView()
                        Text("加载中...")
                            .foregroundColor(.secondary)
                    }
                }
            }
            .navigationTitle("Leagues")
        }
    }
}

3. 优化API请求的安全校验

原请求中强制解包data!会导致空数据崩溃,添加安全校验并处理错误场景:

func getGenres(_ completion: @escaping (CompetitionGroup?) -> ()) {
    let headers = [
        "x-rapidapi-key": "api-key***",
        "x-rapidapi-host": "football-web-pages1.p.rapidapi.com"
    ]
    
    // 校验URL有效性
    guard let url = URL(string: "https://football-web-pages1.p.rapidapi.com/competitions.json?include=rounds") else {
        print("URL无效")
        completion(nil)
        return
    }
    
    var request = URLRequest(url: url, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 10.0)
    request.httpMethod = "GET"
    request.allHTTPHeaderFields = headers
    
    let session = URLSession.shared
    let dataTask = session.dataTask(with: request) { data, response, error in
        if let error = error {
            print("网络请求错误: \(error)")
            completion(nil)
            return
        }
        
        // 校验返回数据非空
        guard let data = data else {
            print("返回数据为空")
            completion(nil)
            return
        }
        
        do {
            let decoder = JSONDecoder()
            let comps = try decoder.decode(CompetitionGroup.self, from: data)
            self.competitions = comps
            completion(comps)
        } catch {
            print("JSON解析错误: \(error)")
            completion(nil)
        }
    }
    
    dataTask.resume()
}

4. 规范ViewController变量声明

确保competitionslist为可选类型,避免未初始化的问题:

var competitionslist: CompetitionGroup? // 明确声明为可选类型

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 03:50:16