这篇文章主要为大家展示了“ios中如何监听reloadData刷新列表完毕的时机”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“ios中如何监听reloadData刷新列表完毕的时机”这篇文章吧。
<强>分析:强>
reloadData是一个异步方法,并不会等待UITableView或者UICollectionView(后面统称listView)真正刷新完毕后才执行后续代码,而是立即执行后续代码。我们执行reloadData的本意是刷新listView,随后会进入一系列的数据源和委托回调,有些是和reloadData同步发生的,有些是异步发生的。
- <李>
同步:numberOfSectionsInCollectionView和numberOfItemsInSection
李> <李>异步:cellForItemAtIndexPath
李> <李>同步+异步:sizeForItemAtIndexPath
李> <强>问题:强>
由于细胞复用的原因,直接在reloadData后执行代码是有可能出问题的。比如在reloadData前保留了一个细胞,在reloadData后,对这个细胞(已经不是原来的细胞了)进行某些操作,会出现一些异常问题。
<强>解决办法:强>
在reloadData前不是保留细胞,二是保留当前细胞对应的NSIndexPath,然后在reloadData完毕(listView真正刷新完毕)后通过方法cellForItemAtIndexPath:重新获取细胞,然后进行相应的操作。
<强>获取listView真正刷新完毕的时机的几种方法强>
方法,通过layoutIfNeeded方法,强制重绘并等待完成。
[self.collectionView reloadData]; [self.collectionView layoutIfNeeded];//,刷新完成,执行后续需要执行的代码 if (, self.didPlayIdx ), { MyCell *,才能cell =, (MyCell *) [self.collectionView cellForItemAtIndexPath self.didPlayIdx):; if 才能;(细胞),{ ,[cell playWithPlayer self.player):; ,,} }
方法2,reloadData方法会在主线程执行,通过肾小球囊性肾病,使后续操作排队在reloadData后面执行。一次runloop有两个机会执行GCD调度队列中主要的任务,分别在休眠前和被唤醒后。设置listView的layoutIfNeeded为是的,在即将进入休眠时执行异步任务,重绘一次界面。
[self.collectionView reloadData];, 设置(dispatch_get_main_queue (),, ^ {,//,才能刷新完成,执行后续代码 if 才能;(),self.didPlayIdx , { ,,,MyCell *, cell =, (MyCell *) [self.collectionView cellForItemAtIndexPath self.didPlayIdx):; ,,,if (细胞),{ ,,,,,[cell playWithPlayer self.player):; ,,,} ,,} });
知识点关联:肾小球囊性肾病死锁,Runloop
//,发生死锁,永远不会执行任务2和3 NSLog (@" 1“); dispatch_sync (dispatch_get_main_queue (),, ^ { NSLog才能(@" 2“); }); NSLog (@" 3“);
方法3、自定义UICollectionView, UITableView, layoutSubviews之后当作reloadData完成(复杂,但可以更好的理解方法一)
# import “MyTableView.h" @interface MyTableView () @property (原子,,复制),void (^ reloadDataCompletionBlock) (); @end @implementation MyTableView 安康;(空白)reloadDataWithCompletion:(void (^) ()) completionBlock { 时间=self.reloadDataCompletionBlock 才能;completionBlock; (才能super reloadData]; } 安康;(空白)layoutSubviews { (才能super layoutSubviews); if 才能;(self.reloadDataCompletionBlock), { ,,,self.reloadDataCompletionBlock (); ,,,self.reloadDataCompletionBlock =,零; ,,} } @end//,调用的时候 [self.tableView reloadDataWithCompletion: ^ { ,,NSLog (@"完成刷新“); }];
<强>引申:更新UI放在主线程的原因强>
<强>原因一:安全+效率强>
因为UIKit框架不是线程安全的,当多个线程同时操作UI的时候,抢夺资源,导致崩溃,UI异常等问题。假如在两个线程中设置了同一张背景图片,很有可能就会由于背景图片被释放两次,使得程序崩溃。或者某一个线程中遍历找寻某个子视图,然而在另一个线程中删除了该子视图,那么就会造成错乱苹果有对大部分的绘图方法和诸如用户界面颜色等类改写成线程安全可用,可还是建议将UI操作保证在主线程中,例如说,我们需要在子线程中读取一个图像对象,使用接口(用户界面图像imageNamed:],但imageNamed:实际上在iOS9以后才是线程安全的,iOS9之前都需要在主线程获取。所以,我们需要从子线程切换到主线程获取图像,然后再切回子线程拿到这个形象,这里我们必须使用同步。