Swift TableViewController:JSON解析先于numberOfRows执行及cellForRowAt未执行问题
异步解析与TableView执行顺序问题解答
嘿,这是Swift新手常遇到的异步操作+TableView生命周期问题,我来帮你拆解清楚:
一、为什么执行顺序是 viewDidLoad → numberOfRows → parse?
核心原因是你的parse()是异步操作(API请求、JSON解析这类网络/耗时任务都是异步的,不会阻塞主线程)。当你在viewDidLoad里调用它时:
- 程序会立刻发起异步解析请求,但不会等它完成,直接执行后面的
print("viewDidLoad"); viewDidLoad执行完毕后,系统会自动触发TableView的数据源方法来初始化界面,所以先调用了numberOfRowsInSection;- 等异步请求/解析真正完成后,才会执行
completionHandler里的代码,也就是print("parse")那部分。
二、怎么让解析完成的逻辑在TableView初始加载前生效?
其实我们没法强制异步任务在TableView初始的numberOfRows之前执行(因为TableView的初始刷新是系统默认流程),但可以通过以下方式保证数据准备好后再正确渲染TableView:
- 绑定数据源数量到数组长度:把
numberOfRowsInSection的返回值设为Info.count,这样初始时数组为空,TableView就知道不需要渲染行; - 确保TableView的代理/数据源正确设置:在
viewDidLoad里加上这两行(你代码里可能漏了):tableView.delegate = self tableView.dataSource = self - 解析完成后强制刷新TableView:你已经写了
tableView.reloadData(),这一步是对的——当Info被赋值后,调用这个方法会重新触发numberOfRowsInSection和cellForRowAt,此时数据已经就绪,就能正确显示了。
如果想让界面更友好,可以初始时隐藏TableView,等数据加载完再显示:
override func viewDidLoad() { super.viewDidLoad() tableView.delegate = self tableView.dataSource = self tableView.isHidden = true // 先隐藏,避免空界面 parse() { result in print("parse") guard let loadedData = result else { return } self.Info = loadedData self.tableView.isHidden = false self.tableView.reloadData() } print("viewDidLoad") }
三、为什么cellForRowAt没有执行?
系统只会在numberOfRowsInSection返回大于0的数值时,才会调用cellForRowAt来创建单元格。
- 初始时你的
Info是空数组,如果numberOfRowsInSection返回的是Info.count(也就是0),系统就知道没有行需要渲染,自然不会调用cellForRowAt; - 等解析完成后调用
tableView.reloadData(),此时Info有数据,numberOfRowsInSection返回对应长度,系统就会触发cellForRowAt了。
最后提个小建议:Swift编码规范里变量名建议用小驼峰,比如把Info改成info,这样代码更易读哦~
内容的提问来源于stack exchange,提问作者Jonossi
相关产品推荐
相关产品推荐

