Swift 5中UITableView返回数组计数时触发数组越界错误
问题分析与修复方案
我来帮你梳理下当前代码里的核心问题,并且给出完整的修复步骤:
核心问题拆解
数组越界错误:你定义的
sample是[News]类型(News对象的数组),但实际上接口返回的是单个News对象(内部包含articles数组)。你解码后把这个单个对象塞进了数组,但是在tableView的数据源方法里直接访问sample[0]——如果网络请求还没完成,sample还是空数组,这时候必然触发数组越界。而且这种数组存储的方式完全没必要,反而增加了复杂度。tableView行数显示异常:你提到返回
sample.count时只显示1个单元格,这是因为sample数组里只有1个元素(你塞进去的那个News对象),所以sample.count等于1,自然只会显示一行。而你真正需要的是articles数组的元素数量。
分步修复
1. 调整数据存储结构
把原来的数组类型存储改成单个可选对象,因为接口返回的是单个News实例:
// 替换原来的 var sample = [News]() var news: News?
2. 修正JSON解码逻辑
在getJson()方法里,直接解码为单个News对象,而不是放到数组中,同时优化遍历和打印逻辑:
func getJson() { // 注意:把url里的&改成&,HTML转义字符在URL里无法被正确识别 let urlString = "https://newsapi.org/v2/top-headlines?country=us&category=business&apiKey=e07d26ea273d41e2af174b026aea27b5" guard let url = URL(string: urlString) else { return } URLSession.shared.dataTask(with: url) { (data, response, error) in guard let data = data else { print("请求无数据返回") return } do { // 直接解码为单个News对象 self.news = try JSONDecoder().decode(News.self, from: data) // 安全打印articles数量 print("文章总数:\(self.news?.articles.count ?? 0)") // 遍历打印标题,避免强制解包 self.news?.articles.forEach { print($0.title ?? "无标题") } DispatchQueue.main.async { self.table.reloadData() } } catch let jsonErr { print("JSON解码错误: ", jsonErr) } }.resume() }
3. 修复tableView数据源方法
修改数据源方法,安全访问数据,避免空值和越界:
extension ViewController: UITableViewDataSource, UITableViewDelegate { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { // 如果news为空,返回0;否则返回articles的数量 return news?.articles.count ?? 0 } func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { return 100 } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "TableViewCell") as! TableViewCell // 安全获取当前行的文章数据,避免越界和空值 guard let article = news?.articles[indexPath.row] else { cell.name.text = "无标题" cell.link.text = "无描述" cell.imageUrl.text = "无图片链接" return cell } // 用空合并运算符处理可选值,防止崩溃 cell.name.text = article.title ?? "无标题" cell.link.text = article.description ?? "无描述" cell.imageUrl.text = article.urlToImage ?? "无图片链接" return cell } }
4. 额外的安全优化
- 把URL中的
&替换为&:因为&是HTML的转义字符,直接放在URL里会导致请求参数解析错误,可能返回非预期的结果。 - 避免所有的强制解包(
!):改用可选绑定(guard let)或空合并运算符(??)处理可选值,防止因为接口返回null或者数据未加载完成导致崩溃。
完整修正后的代码
import UIKit struct News: Decodable { let articles: [Article] struct Article: Decodable { let title: String? let urlToImage: String? let description: String? } } class ViewController: UIViewController { @IBOutlet weak var table: UITableView! // 调整为单个可选对象 var news: News? override func viewDidLoad() { super.viewDidLoad() getJson() table.delegate = self table.dataSource = self } func getJson() { // 修正URL中的转义字符 let urlString = "https://newsapi.org/v2/top-headlines?country=us&category=business&apiKey=e07d26ea273d41e2af174b026aea27b5" guard let url = URL(string: urlString) else { return } URLSession.shared.dataTask(with: url) { (data, response, error) in guard let data = data else { print("请求无数据返回") return } do { self.news = try JSONDecoder().decode(News.self, from: data) print("文章总数:\(self.news?.articles.count ?? 0)") self.news?.articles.forEach { print($0.title ?? "无标题") } DispatchQueue.main.async { self.table.reloadData() } } catch let jsonErr { print("JSON解码错误: ", jsonErr) } }.resume() } } extension ViewController: UITableViewDataSource, UITableViewDelegate { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return news?.articles.count ?? 0 } func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { return 100 } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "TableViewCell") as! TableViewCell guard let article = news?.articles[indexPath.row] else { cell.name.text = "无标题" cell.link.text = "无描述" cell.imageUrl.text = "无图片链接" return cell } cell.name.text = article.title ?? "无标题" cell.link.text = article.description ?? "无描述" cell.imageUrl.text = article.urlToImage ?? "无图片链接" return cell } }
内容的提问来源于stack exchange,提问作者Stephenson Ang
相关产品推荐
相关产品推荐

