美文网首页
NSRunLoop之入门理解(二)

NSRunLoop之入门理解(二)

作者: J了个朋 | 来源:发表于2017-08-08 22:05 被阅读0次

    使用NSRunLoop优化界面卡的现象

    1 一般UI加载是在主线程执行,避免多线程抢夺资源的情况,所以也就设置成nonatomic属性即非原子属性,那么当太多的数据需要加载的时候尤其指超高清的大图片等,这时候用户在操作比如下滑cell等就会造成很(狠)明显的UI卡顿现象,这时候使用NSRunLoop就可以优化
    2 使用一个数组添加block,然后在block里面执行需要操作的任务-这里表示UI的加载
    3 需要一个CFRunLoopObserverRef观察者,把VC对象传到context里面,调用VC的block执行任务
    #import "JRunLoopDemo.h"
    
    typedef void(^RunLoopBlock)();
    
    @interface JRunLoopDemo ()<UITableViewDelegate,UITableViewDataSource>
    @property (weak, nonatomic) IBOutlet UITableView *mainTabbleView;
    ///定义一个block
    @property (strong, nonatomic)  NSMutableArray *tasks;//添加任务
    @property (assign, nonatomic)  NSUInteger maxQueueLenth;//最大任务
    @end
    
    @implementation JRunLoopDemo
    /*
     UIKIt 是不安全的 因为上锁需要消耗性能 
     UI直接反应用户体验
     苹果粑粑建议对UI操作放在主线程 不要出现抢夺资源的情况
     */
    - (void)viewDidLoad {
        [super viewDidLoad];
        self.tasks = [NSMutableArray array];
        [NSTimer scheduledTimerWithTimeInterval:0.001 repeats:YES block:^(NSTimer * _Nonnull timer) {
                [self addRunLoopObserver];
        }];
    }
    
    #pragma mark - UITableViewDelegate && UITableViewDataSource
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
        return  100;
    }
    
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"123"];
        
        if (!cell) {
            cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:@"123"];
        }
            // [self cellAddSubview:cell];
           // [self cellAddSubview:cell];
           // [self cellAddSubview:cell];
           // [self cellAddSubview:cell];
           // [self cellAddSubview:cell];
        
        __weak typeof(self) weakSelf = self;
        [self addTask:^{
                [weakSelf cellAddSubview:cell];
        }];
        [self addTask:^{
            [weakSelf cellAddSubview:cell];
        }];
        [self addTask:^{
            [weakSelf cellAddSubview:cell];
        }];
        
        return cell;
    }
    
    - (void)cellAddSubview:(UITableViewCell *)cell{
        
        for (int i=0;i<100; i++) {
            UIView *view = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 320, 120)];
            view.backgroundColor = [UIColor redColor];
            [cell addSubview:view];
        }
    }
    
    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        return 200;
    }
    /// 添加任务
    - (void)addTask:(RunLoopBlock)task {
       
     [self.tasks addObject:task];
        if (self.tasks.count > self.maxQueueLenth) {
            [self.tasks removeObjectAtIndex:0];
        }
        
    }
    /// 添加观察者
    - (void)addRunLoopObserver{
        
        // 拿到当前的RunLoop
        CFRunLoopRef runLoop =  CFRunLoopGetCurrent();
        //上下文
        CFRunLoopObserverContext context = {
          0,
            (__bridge void*)(self),
            &CFRetain,
            &CFRelease,
            NULL
        };
        // 定义一个观察者
        static CFRunLoopObserverRef defautModelObserver;
        // 创建一个观察者
       defautModelObserver = CFRunLoopObserverCreate(NULL,   
       kCFRunLoopBeforeWaiting, YES, 0, &Callback, &context);
       // 添加观察者
        CFRunLoopAddObserver(runLoop, defautModelObserver, kCFRunLoopCommonModes);
         CFRelease(defautModelObserver);
      }
    /// 定义一个函数。然后让他不断执行
    static void Callback(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info){
        
        JRunLoopDemo *runLoopVC = (__bridge JRunLoopDemo *)info;
        if (runLoopVC.tasks.count == 0)  return;
        RunLoopBlock task =  runLoopVC.tasks[0];
        task();//执行这个任务
        //执行完毕 删除任务
        [runLoopVC.tasks removeObjectAtIndex:0]; 
    }
    @end
    

    总结:核心代码是这里面的kCFRunLoopCommonModes 模式等同于NSDefaultRunLoopMode和UITrackingRunLoopMode叠加

    // 添加观察者
    CFRunLoopAddObserver(runLoop, defautModelObserver, kCFRunLoopDefaultMode);

    另外

    CFRunLoopObserverContext context = {
    
      0,
        (__bridge void*)(self),
        &CFRetain,
        &CFRelease,
        NULL
    };
    

    把self传到Callback函数,可以在这里得到self的task() 这个block,然后直接跳用

    相关文章

      网友评论

          本文标题:NSRunLoop之入门理解(二)

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