您的位置:首页 > 产品设计 > UI/UE

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: