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

如何让completion Handler内代码在UICollectionViewCell初始化前执行

问题原因

网络请求fetchNewsData是异步执行的,发起请求后不会阻塞主线程等待结果返回,所以viewDidLoad里的执行顺序是:

  1. 触发网络请求
  2. 立刻执行请求外的collectionView.reloadData(),此时newsArray还是空数组,CollectionView开始调用数据源方法初始化Cell
  3. 后续网络请求成功返回后,才会执行completion回调里的代码填充newsArray

另外你在cellForItemAt方法里调用collectionView.reloadData()属于严重错误:每次Cell生成都会触发CollectionView全局刷新,会无限循环调用数据源方法,造成性能问题甚至崩溃。


修复方案

你需要修改3个核心点:

  • 把collectionView.reloadData()移到网络请求的completion回调末尾,且所有UI操作必须切换到主线程执行
  • 不要写死返回10个Item,数量和newsArray的长度绑定,避免数组越界崩溃
  • 删除cellForItemAt里的刷新代码

修改后完整代码

class NewsViewController: UIViewController {
    
    let networkManager = NetworkManager()
    var newsArray = [NewsModel]()
    var totalResult:Int = 0
    
    @IBOutlet weak var collectionView: UICollectionView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // 若未在Storyboard中设置,需手动绑定delegate和dataSource
        collectionView.delegate = self
        collectionView.dataSource = self
        
        networkManager.fetchNewsData(forCoutry: "us", category: "business") { newsDataModel in
            
            self.totalResult = newsDataModel.totalResults
            
            for article in newsDataModel.articles {
                let news = NewsModel(newsTitle: article.title,
                                     urlToNewsWebSite: article.url,
                                     authorWebSiteName: article.source.name,
                                     urlToImage: article.urlToImage ?? "" )
                
                self.newsArray.append(news)
            }
            
            // 网络请求回调默认在子线程,UI操作必须切到主线程执行
            DispatchQueue.main.async {
                self.collectionView.reloadData()
            }
        }
    }
    
}

extension NewsViewController: UICollectionViewDelegate {
    
}

extension NewsViewController: UICollectionViewDataSource {
    
    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 1
    }
    
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        // 数量和数组长度绑定,请求未返回时显示0个Cell,避免数组越界
        return newsArray.count
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "item", for: indexPath) as! NewsCell
        cell.configureCell()
        cell.initData(news: newsArray[indexPath.item])
        return cell
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 21:36:03