引子和思路
runloop是每次循环就会渲染屏幕上所有的点,当我们在做一个table上显示很多张图片时,拖动table,会感觉到明显的卡顿,就是因为每一次我们拖动table,runloop循环就会加载渲染一次,所以十分耗时,思路是我们分成图片数量次加载,每一次只加载一张图片,一次一次的加载。
demo在文章最下面放出。
实现流程
把每一次需要加载cell的代码包装成一个任务(block),放到数组里面。
//MARK: 添加任务
-(void)addTask:(RunloopBlock)unit withKey:(id)key{
[self.tasks addObject:unit];
[self.tasksKeys addObject:key];
//保证之前没有显示出来的任务,不再浪费时间加载
if (self.tasks.count > self.max) {
[self.tasks removeObjectAtIndex:0];
[self.tasksKeys removeObjectAtIndex:0];
}
}
然后写一个方法去监听runloop,每一次循环只在数组里面取一个任务去执行。我们需要用到�CoreFoundation框架中的CFRunloop,找到其中的Observer观察者,每一条都代表着runloop的一种状态。
kCFRunLoopEntry 进入一次循环
kCFRunLoopBeforeTimers 处理timers之前
kCFRunLoopBeforeSources 处理sources之前
kCFRunLoopBeforeWaiting 即将进入睡眠状态
kCFRunLoopAfterWaiting 从睡眠状态即将处理事件
kCFRunLoopExit 退出
kCFRunLoopAllActivities 所有的事件
了解了这些,开始进行监听runloop,并需要在viewdidload中启动观察者。
//这里面都是C语言 -- 添加一个监听者
-(void)addRunloopObserver{
//获取当前的RunLoop
CFRunLoopRef runloop = CFRunLoopGetCurrent();
//定义一个context 上下文
CFRunLoopObserverContext context = {
0,
( __bridge void *)(self), // info 传入了self 下面获取当前控制器
&CFRetain,
&CFRelease,
NULL
};
//定义一个观察者
static CFRunLoopObserverRef defaultModeObsever;
//创建观察者
defaultModeObsever = CFRunLoopObserverCreate(NULL,
kCFRunLoopBeforeWaiting,
YES,
NSIntegerMax - 999,
&Callback,
&context
);
//添加当前RunLoop的观察者
CFRunLoopAddObserver(runloop, defaultModeObsever, kCFRunLoopDefaultMode);
//c语言有creat 就需要release
CFRelease(defaultModeObsever);
}
由于runloop每次之行结束就会进入睡眠状态,但是我们需要让他一直不睡眠,一直执行,这里使用一个NSTimer,绑定一个事件,每0.1秒执行一次。事件什么都不需要做,只是为了让runloop一直都是唤醒状态。
接下来,需要定义上面的callback回调函数,并且每一次runloop循环只回调一次。
//MARK: 回调函数
//定义一个回调函数 一次RunLoop来一次
// 这三个参数 会默认传递给这个方法 根据这个info才能取到当前控制器
static void Callback(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info){
ViewController * vc = (__bridge ViewController *)(info);
if (vc.tasks.count == 0) {
return;
}
BOOL result = NO;
while (result == NO && vc.tasks.count) {
//取出任务
RunloopBlock unit = vc.tasks.firstObject;
//执行任务
result = unit();
//干掉第一个任务
[vc.tasks removeObjectAtIndex:0];
//干掉标示
[vc.tasksKeys removeObjectAtIndex:0];
}
}