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

