NSRunLoop之入门理解(二)

使用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 ()
@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之入门理解(二))