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

Swift中获取NewsAPI的JSON数据后无法在UITableView展示

iOS新闻应用UITableView空白问题修复

问题背景

基于News API开发iOS新闻应用,主屏幕使用UITableView展示当日头条新闻的配图与标题,实际运行时列表完全空白,无任何内容渲染。
已验证数据拉取与JSON解析环节正常:接口请求成功后可正常打印所有头条标题,解析后的数据会存入topNewsArray数组,数组元素为CellArticle结构体实例,存储单条新闻的标题、配图资源信息;无可用配图的新闻默认标记使用SF Symbols提供的newspaper报纸图标。

现有问题代码

新闻数据拉取逻辑

func getTopNews() {
        
        currentLocation = Locale.current.regionCode?.lowercased() ?? "us"
        let urlString: String = "https://newsapi.org/v2/top-headlines?country=\(currentLocation)&apiKey=\(apiKey)"
        let url = URL(string: urlString)
        
        // 校验URL有效性
        guard url != nil else {
            return
        }
        
        let session = URLSession.shared
        
        let dataTask = session.dataTask(with: url!) { data, response, error in
            
            // 校验请求无错误、返回数据存在
            if error == nil && data != nil {
                
                let decoder = JSONDecoder()
                
                do {
                    
                    let topNewsFeed = try decoder.decode(NewsFeed.self, from: data!)
                    let topNewsCount: Int = (topNewsFeed.articles?.count)!
                    
                    // 将新闻数据写入topNewsArray
                    for i in 0..<topNewsCount {
                        
                        let cellTitle = topNewsFeed.articles?[i].title
                        
                        if topNewsFeed.articles?[i].urlToImage != nil {
                            let cellImage = topNewsFeed.articles?[i].urlToImage
                            self.topNewsArray.append(CellArticle(title: cellTitle, imageName: cellImage))
                        }
                        else {
                            self.topNewsArray.append(CellArticle(title: cellTitle, imageName: "newspaper"))
                        }
                        print("News Title: ", cellTitle!, "\n")
                        
                    }
                }
                
                catch {
                    print("Error in JSON Parsing.")
                }
            }
        }
        
        // 发起API请求
        dataTask.resume()
        
    }

单元格填充代理逻辑

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        let currentArticle = topNewsArray[indexPath.row]
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CustomTableViewCell
        
        cell.label.text = currentArticle.title
        
        if currentArticle.imageName == "newspaper" {
            cell.iconImageView.image = UIImage(systemName: "newspaper")
        }
        else {
            let urlToImage = URL(string: currentArticle.imageName!)
            let dataImage = try? Data(contentsOf: urlToImage!)
            cell.iconImageView.image = UIImage(data: dataImage!)
        }
        
        
        return cell
    }

问题根因

  • 核心问题:URLSession的网络请求回调默认运行在后台子线程,你在回调中完成topNewsArray数据填充后,没有回到主线程调用tableView.reloadData()触发列表渲染。UIKit框架要求所有UI相关操作必须在主线程执行,不主动触发刷新的话,tableView无法感知数据更新,自然不会加载任何单元格。
  • 潜在崩溃隐患:在cellForRowAt代理方法中使用Data(contentsOf:)同步加载网络图片,会阻塞调用线程;同时代码中多处对可选值做强制解包,一旦图片URL失效、网络请求失败,会直接触发应用崩溃。

修复步骤

  1. 补全列表刷新逻辑:在数据解析完成、topNewsArray填充结束后,切换到主线程调用tableView刷新方法。修改getTopNews方法中do块内的for循环,在循环结束后添加如下代码:
// 所有新闻数据存入数组后执行
DispatchQueue.main.async {
    // 替换为你实际的tableView属性名
    self.tableView.reloadData()
}

UI操作必须在主线程执行是UI开发的基础规则,任何后台线程更新UI的操作都会导致渲染异常甚至崩溃。

  1. 优化图片加载逻辑,移除同步加载与强制解包,避免卡顿和崩溃,替换后的cellForRowAt代码如下:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let currentArticle = topNewsArray[indexPath.row]
    let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CustomTableViewCell
    
    cell.label.text = currentArticle.title
    // 设置默认占位图,避免单元格复用导致的内容错乱
    cell.iconImageView.image = UIImage(systemName: "newspaper")
    
    // 校验图片URL有效性,避免强制解包
    if currentArticle.imageName != "newspaper",
       let imagePath = currentArticle.imageName,
       let imageUrl = URL(string: imagePath) {
        // 异步加载网络图片,不阻塞主线程
        URLSession.shared.dataTask(with: imageUrl) { [weak self] data, _, error in
            guard let data = data, error == nil, let loadImage = UIImage(data: data) else {
                return
            }
            DispatchQueue.main.async {
                // 校验单元格位置,避免复用导致的图片错位
                if let targetCell = tableView.cellForRow(at: indexPath) as? CustomTableViewCell {
                    targetCell.iconImageView.image = loadImage
                }
            }
        }.resume()
    }
    return cell
}
  1. 基础配置校验
  • 确认tableView的dataSource、delegate已经正确关联到当前控制器(代码设置或Storyboard拖线均可)
  • 确认单元格重用标识符"cell"与Storyboard中配置的标识符完全一致,CustomTableViewCell类已经正确绑定到对应单元格
  • 确认getTopNews()方法在控制器生命周期中被正常调用,比如在viewDidLoad方法中调用

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 00:48:25