美文网首页
Runloop 之 性能优化

Runloop 之 性能优化

作者: 有梦想的狼 | 来源:发表于2020-03-06 15:20 被阅读0次

    案例:tableView的Cell中有多个ImageView,同时加载大图,导致UI卡顿。
    解决思路:使用Runloop每次循环址添加一张图片。
    工具:这里我们需要使用到CFRunloop

    实现过程:

    1、把加载图片等代码保存起来,先不执行 (保存一段代码,block)
    2、监听Runloop循环(CFRunloopObserver)
    3、每次都从任务数组中取出一个加载图片等代码执行(执行block代码)

    监听Runloop

    //添加runloop监听者
    - (void)addRunloopObserver{
        
        //    获取 当前的Runloop ref - 指针
        CFRunLoopRef current =  CFRunLoopGetCurrent();
        
        //定义一个RunloopObserver
        CFRunLoopObserverRef defaultModeObserver;
        
        //上下文
        /*
         typedef struct {
            CFIndex version; //版本号 long
            void *  info;    //这里我们要填写对象(self或者传进来的对象)
            const void *(*retain)(const void *info);        //填写&CFRetain
            void    (*release)(const void *info);           //填写&CGFRelease
            CFStringRef (*copyDescription)(const void *info); //NULL
         } CFRunLoopObserverContext;
         */
        CFRunLoopObserverContext context = {
            0,
            (__bridge void *)(self),
            &CFRetain,
            &CFRelease,
            NULL
        };
        
        /*
         1 NULL空指针 nil空对象 这里填写NULL
         2 模式
            kCFRunLoopEntry = (1UL << 0),
            kCFRunLoopBeforeTimers = (1UL << 1),
            kCFRunLoopBeforeSources = (1UL << 2),
            kCFRunLoopBeforeWaiting = (1UL << 5),
            kCFRunLoopAfterWaiting = (1UL << 6),
            kCFRunLoopExit = (1UL << 7),
            kCFRunLoopAllActivities = 0x0FFFFFFFU
         3 是否重复 - YES
         4 nil 或者 NSIntegerMax - 999
         5 回调
         6 上下文
         */
        //    创建观察者
        defaultModeObserver = CFRunLoopObserverCreate(NULL,
                                                      kCFRunLoopBeforeWaiting, YES,
                                                      NSIntegerMax - 999,
                                                      &Callback,
                                                      &context);
        
        //添加当前runloop的观察着
        CFRunLoopAddObserver(current, defaultModeObserver, kCFRunLoopDefaultMode);
        
        //释放
        CFRelease(defaultModeObserver);
    }
    

    我们要实现回调方法:

    static void Callback(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info){
        
        //通过info桥接为当前的对象
        PQRunloop * runloop = (__bridge PQRunloop *)info;
        
        //如果没有任务,就直接返回
        if (runloop.tasks.count == 0) {
            return;
        }
        
        BOOL result = NO;
        while (result == NO && runloop.tasks.count) {
            
            //取出任务
            RunloopBlock unit = runloop.tasks.firstObject;
            
            //执行任务
            result = unit();
            
            //删除任务
            [runloop.tasks removeObjectAtIndex:0];
        }
    }
    //因为在C方法中没有办法调用OC对象,所以context中有一个void * info,为的就是解决这个问题,把OC的对象传入到回调方法中。
    

    通过上面的两个方法我们可以做到监听Runloop循环,以及每次循环需要处理的事情,这个时候我们只需要对外提供一个添加任务的方法,用数组保存起来。

    //add task 添加任务
    - (void)addTask:(RunloopBlock)unit withId:(id)key{
        //添加任务到数组
        [self.tasks addObject:unit];
        [self.taskKeys addObject:key];
        
        //为了保证加载到图片最大数是18所以要删除
        if (self.tasks.count > self.maxQueue) {
            [self.tasks removeObjectAtIndex:0];
            [self.taskKeys removeObjectAtIndex:0];
        }
    }
    

    Dome码源

    相关文章

      网友评论

          本文标题:Runloop 之 性能优化

          本文链接:https://www.haomeiwen.com/subject/ruhirhtx.html