TableView卡顿环境分析:
tableView加载过多的高清大图,Runloop不只处理iOS事件,渲染图形也是runloop处理的。
而渲染图形的UI操作必须在主线程中,不能开辟线程进行图形处理。
在拖动tableView的时候,Runloop要处理拖动事件,还要处理过多图片渲染,而造成卡顿。
解决卡顿分析:
1、Runloop在一次循环渲染图片过多,那就让Runloop一次处理一张图片
2、将处理图片的代码放在block中,然后加入数组中,处理几次加入几次。
3、我们只需要渲染,tableView显示的图片,显示图片有最大个数。移开屏幕或者不处理的从队列数组里删去。
2和3其实就是逻辑的问题,不赘述了,下面会给出demo源码。主要讲讲第一个问题,是处理卡顿的重点。
第一个问题实现代码如下:
#pragma mark 设置runloop监听
//这里面都是C语言 -- 添加一个监听者
-(void)addRunloopObserver{
//获取当前runloop
CFRunLoopRef currentRunloop = CFRunLoopGetCurrent();
//runloop观察者上下文, 为下面创建观察者准备,只有创建上下文才能在回调了拿到self对象,才能进行我们的逻辑操作. 这是一个结构体。
/**
typedef struct {
CFIndex version;
void * info;
const void *(*retain)(const void *info);
void (*release)(const void *info);
CFStringRef (*copyDescription)(const void *info);
} CFRunLoopObserverContext;
**/
CFRunLoopObserverContext context = {
0,
(__bridge void *)(self),
&CFRetain,
&CFRelease,
NULL
};
//创建Runloop观察者 kCFRunLoopBeforeWaiting 观察在等待状态之前 runloop有下面几种状态 看英文应该知道了。
/*
kCFRunLoopEntry = (1UL << 0),
kCFRunLoopBeforeTimers = (1UL << 1),
kCFRunLoopBeforeSources = (1UL << 2),
kCFRunLoopBeforeWaiting = (1UL << 5),
kCFRunLoopAfterWaiting = (1UL << 6),
kCFRunLoopExit = (1UL << 7),
kCFRunLoopAllActivities = 0x0FFFFFFFU
*/
static CFRunLoopObserverRef obserberRef;
obserberRef =CFRunLoopObserverCreate(NULL, kCFRunLoopBeforeWaiting, YES, 0,&callback, &context);
//给当前runloop添加观察者
CFRunLoopAddObserver(currentRunloop, obserberRef, kCFRunLoopDefaultMode);
//释放观察者
CFRelease(obserberRef);
}
//观察回调
static void callback(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info){
ViewController * vcSelf = (__bridge ViewController *)(info);
if (vcSelf.TaskMarr.count > 0) {
//获取一次数组里面的任务并执行
runloopTask task = vcSelf.TaskMarr.firstObject;
task();
[vcSelf.TaskMarr removeObjectAtIndex:0];
}else{
return;
}
}
- 先推理下,如果我要把任务放到Runloop里操作,首先我要获取Runloop。
- 然后我们需要一个观察者,找一个时机把任务放进去。如果对runloop了解的话,会想到CFRunLoopObserver.然后我们创建一下这个观察者对象。
- 然后把观察者扔进runloop,这样我们就能拿到,Runloop等待之前的回调。
- 然后把任务扔到回调中。
方案如下:
//给runloop一个事件源,让Runloop不断的运行执行代码块任务。
[NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(runloopalive) userInfo:nil repeats:YES];
//如果方法里什么都不干,APP性能影响并不大。但cpu增加负担,
-(void)runloopalive{
//什么都不干
}
demo地址:https://github.com/RainManGO/tableView-Caton-optimization