在很久很久以前,iOS工程师也叫‘tableBoy’,因为你只需要熟练使用‘tableView’就可以完成大部分的功能需求。但是现在来看,玩好‘tableView’并不简单。 前几天,同学收到了一个闪退的信息,对应符号表一看‘tableview willDisplay’出现了数组越界。这种情况好像不太常见,像是‘table reload’的时候修改了源数据造成的,没有考虑到多线程安全。接着,我们分析了一波代码大概是这样的场景:‘Pull Refresh 和 ViewController willAppear 都会触发一个异步线程请求数据,数据返回后在主线程修改源数据并且执行reload’,因为都是主线程修改源数据,并不存在多线程安全问题。同学表示很暴躁,直接一个数据越界的保护,该问题就当修复了。 #定位

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath)

在tableview中你调用reloaddata,如上2个函数是不会在当前调用栈上执行,数组越界的问题的确是异步造成的。

#解决

暴力法

添加数据越界的保护,从逻辑上看,Cell页面应该会出现空白或者异常数据;但是因为下一次reload立马执行了,视觉上应该是无法感知的。

降温法

既然是因为同时多个线程修改源数据导致,可以创建个队列一个个来,保证修改数据源的安全的有效的。

reload执行’完毕’

其实iOS11后,tableView提供了一个函数,替换原先的beginUpdate 和 endUpdate,并且回调执行完成的结果

    // Reloading and Updating
    
    // Allows multiple insert/delete/reload/move calls to be animated simultaneously. Nestable.
    @available(iOS 11.0, *)
    open func performBatchUpdates(_ updates: (() -> Void)?, completion: ((Bool) -> Void)? = nil)

我尝试在willDisplay sleep(1),当reload执行‘完毕’后,completion会回调。 那么11之前怎么确定呢?自己去寻找答案吧 Demo