CFRunloop 优化TableView加载高清大图UI卡顿问题。单独分批加载

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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券