深入reloadData

1.runloop在执行任务时循环速度很快,一秒钟要循环多次,当发现没有内核mach_msg事件后,进入睡眠,每隔一分钟循环一次。

2.监听reloadData完成

先来看看执行reloadData都发生了什么。
reloadData是一个异步方法,更具体点来说,是reloadData这个调用中包含了异步操作。
当我们reloadData的时候,我们本意是刷新UITableView,随后会进入一系列UITableViewDataSource和UITableViewDelegate的回调,其中有些是和reloadData同步发生的,有些则是异步发生的。

  • 同步:
    tableView:numberOfRowsInSection:
  • 异步:
    tableView:cellForRowAtIndexPath:
  • tableView:heightForRowAtIndexPath:这个方法有些特殊,在同步和异步的时候都进行了回调。

一次runloop有两个机会执行GCD dispatch main queue中的任务,分别在休眠前和被唤醒后。设置tableView layoutIfNeeded为YES,在即将进入休眠时执行异步任务,重绘一次界面。

所以监听reloadData完成可以有两种方法

方法一:唤醒时刻当作reloadData完成

dispatch_async(dispatch_get_main_queue(), ^{
    _isReloadDone = NO;
    [tableView reload]; //会自动设置tableView layoutIfNeeded为YES,意味着将会在runloop结束时重绘table
    dispatch_async(dispatch_get_main_queue(),^{
        _isReloadDone = YES;
    });
});

方法二:自定义UITableView,layoutSubviews之后当作reloadData完成(复杂,但可以更好的理解方法一)

#import "DBTableView.h"

@interface DBTableView()

@property (nonatomic, copy) void (^reloadDataCompletionBlock)();

@end

@implementation DBTableView

- (void)reloadDataWithCompletion:(void (^)())completionBlock {
    self.reloadDataCompletionBlock = completionBlock;
    [super reloadData];
}

- (void)layoutSubviews {
    [super layoutSubviews];
    if (self.reloadDataCompletionBlock) {
        self.reloadDataCompletionBlock();
        self.reloadDataCompletionBlock = nil;
    }
}

@end

调用的时候

[self.tableView reloadDataWithCompletion:^{
     NSLog(@"完成刷新");
}];

在主线程中执行dispatch_async(dispatch_get_main_queue()做了什么?

通常我们在子线程任务结束后使用dispatch_async(dispatch_get_main_queue()来回到主线程刷新UI,那么在主线程使用它是为了什么呢?

情景:在快速滑动的时候reload

dispatch_async(dispatch_get_main_queue(), ^{
     [tableView reloadData]; 
});

加入主队列后,会在合适的一次loop循环中进行reload操作,并且在这次loop中渲染cell,实现流畅的滑动。
而没有加入主队列的reload,渲染cell的时机不固定。一般发生跳屏、白屏,就是因为需要等到tableView停下才会继续渲染cell。

参考链接:
iOS 事件处理机制与图像渲染过程

你可能感兴趣的:(深入reloadData)