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

Swift:ViewDidLoad中异步函数未完成数据解码时CollectionView提前加载导致Nil错误的解决方法

解决CollectionView在数据解码完成前加载的问题

我来帮你搞定这个异步请求导致的nil错误问题~核心原因是网络请求是异步执行的,viewDidLoad走完后CollectionView会立刻尝试读取数据源,但此时subCategoryModel还没被赋值,自然会报错。咱们可以从这几个方向调整代码:

1. 先给CollectionView加“安全防护”

在CollectionView的数据源方法里,先判断数据是否存在,避免直接访问nil值:

// 示例:返回item数量的方法
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    // 如果模型为空,返回0个item,避免CollectionView加载空数据
    return subCategoryModel?.subCategories?.count ?? 0
}

// 示例:配置cell的方法
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "YourCellID", for: indexPath) as! YourCustomCell
    
    // 先安全解包模型和对应位置的数据
    guard let model = subCategoryModel,
          let categoryItem = model.subCategories?[indexPath.item] else {
        return cell
    }
    
    // 这里用有效数据配置cell
    cell.categoryLabel.text = categoryItem.name
    return cell
}

2. 数据解码完成后,手动触发CollectionView刷新

网络请求的回调是在后台线程执行的,所以解码完成后必须切回主线程刷新UI,确保CollectionView在数据准备好后才加载:

func getSubCategories(){ 
    let parameters = xx 
    let url = URL(string: "xx")! 
    let session = URLSession.shared 
    var request = URLRequest(url: url) 
    request.httpMethod = "POST" 
    do { 
        request.httpBody = try JSONSerialization.data(withJSONObject: parameters, options: .prettyPrinted) 
    } catch let error { 
        print(error.localizedDescription) 
    } 
    let task = session.dataTask(with: request, completionHandler: { [self] data, response, error in 
        // 先处理错误情况
        if let error = error {
            print("请求失败:\(error.localizedDescription)")
            return
        }
        guard let responseData = data else {
            print("未获取到有效数据")
            return
        }
        
        do {
            subCategoryModel = try JSONDecoder().decode(SubCategoryModel.self, from: responseData)
            print(subCategoryModel!)
            
            // 切回主线程刷新CollectionView
            DispatchQueue.main.async {
                self.yourCollectionView.reloadData()
            }
        } catch let error { 
            print("解码错误:\(error)") 
        } 
    }) 
    task.resume() 
}

3. 可选优化:给用户加载反馈

如果想提升体验,可以在viewDidLoad里添加一个加载指示器,数据加载完成后再隐藏并刷新:

// 先在视图里添加加载指示器
let loadingIndicator = UIActivityIndicatorView(style: .large)

override func viewDidLoad(){ 
    super.viewDidLoad() 
    yourCollectionView.delegate = self
    yourCollectionView.dataSource = self
    
    // 配置加载指示器
    loadingIndicator.center = view.center
    loadingIndicator.hidesWhenStopped = true
    view.addSubview(loadingIndicator)
    
    // 启动加载并请求数据
    loadingIndicator.startAnimating()
    getSubCategories() 
}

// 然后在网络请求完成后更新UI
DispatchQueue.main.async {
    self.loadingIndicator.stopAnimating()
    self.yourCollectionView.reloadData()
}

这样调整后,CollectionView只会在数据真正准备好之后才会刷新加载,再也不会出现nil错误啦~

内容的提问来源于stack exchange,提问作者Bilal Mughal

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 09:37:39