CFRunloop 优化TableView加载高清大图UI卡顿问题。单独分批加载
2017-06-08 16:50
393 查看
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不断的运行,直到你的任务结束。
方案如下:
//给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
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不断的运行,直到你的任务结束。
方案如下:
//给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
相关文章推荐
- 详解Android_性能优化之ViewPager加载成百上千高清大图oom解决方案
- Android_性能优化之ViewPager加载成百上千高清大图oom解决方案
- Android_性能优化之ViewPager加载成百上千高清大图oom解决方案
- Android_性能优化ViewPager加载高清大图oom解决方案
- ListView卡顿优化过程,并解决与viewpager图片加载冲突的问题
- ios-UI常见问题之TableView异步加载图片错乱显示
- 多个ImageView 加载高清大图的内存管理
- iOS开发经验之多个UIImageView 加载高清大图时内存管理
- ios tableView 的header for section无法加载的问题
- IOS多个UIImageView加载高清大图时内存管理
- iOS tableView 异步加载图片时错位问题
- UIImageView 加载高清大图时内存管理
- 优化tableView加载cell与model的过程
- 关于tableview 加载数据,性能优化
- android UI 优化之<viewstub>实现View的延迟加载
- 优化tableView的卡顿
- Android之打造自己加载高清大图及瀑布流框架.解决错位等问题.
- UI—UITableView的性能优化、plist文件的加载
- UI tableView 的优化
- IOS 多个UIImageView 加载高清大图时内存管理