RunLoop应用

282 阅读2分钟

控制线程的生命周期

在主动结束线程前,使线程一直存在

  • 初始化设置
- (instancetype)init {
    
    self = [super init];
    if (self) {
        self.stoped = NO;
        __weak typeof(self) weakSelf = self;
        self.innerThread = [[AZThread alloc] initWithBlock:^{
            
            //方式一: NSRunLoop
//            [[NSRunLoop currentRunLoop] addPort:[[NSPort alloc] init] forMode:NSDefaultRunLoopMode];
//            while (weakSelf && !weakSelf.stoped) {
//                [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
//            }
            
            //方式二: CFRunLoop
            CFRunLoopSourceContext context = {0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
            CFRunLoopSourceRef source = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context);
            CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
            //如果可以运行
            while (weakSelf && !weakSelf.stoped) {
                NSLog(@"RunLoop1");
                @autoreleasepool {
                    CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1.0e10, true);
                }
                NSLog(@"RunLoop2");
            }
            //某一时机,静态变量runAlways变为NO时,保证跳出RunLoop,线程推出
            CFRunLoopRemoveSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
            CFRelease(source);
            NSLog(@"exist");

        }];
            }
    return self;
}
  • 开始
- (void)run{
    if (!self.innerThread) return;
    [self.innerThread start];
}
  • 执行
- (void)excuteTask:(AZblock)block {
    if (!self.innerThread || !block) return;
    [self performSelector:@selector(task:) onThread:self.innerThread withObject:block waitUntilDone:NO];
}

- (void)task:(AZblock)block {
    block();
}
  • 结束
- (void)stop {
    if (!self.innerThread) return;
    [self performSelector:@selector(__stop) onThread:self.innerThread withObject:nil waitUntilDone:YES];
}

- (void)__stop {
    self.stoped = YES;
    CFRunLoopStop(CFRunLoopGetCurrent());
    self.innerThread = nil;
}

- (void)dealloc {
    NSLog(@"%s", __func__);
    [self stop];
}

线程中添加NSTimer

NSTimer在线程中将不影响主线程操作。
NSTimer的运行基于RunLoop,主线程[NSTimer scheduledTimerWithTimeInterval:target: selector: userInfo: repeats:]方法会自动加入runloop中。 主线程中处理复杂的UI界面时,NSTimer将被阻塞。

/**
 添加runloop
 */
- (void)run:(id)__unused object {
    @autoreleasepool {
        NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
        [runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
        
        
        // 添加timer
        [self addTimerToRunLoop];

        [runLoop run];
    }
}

- (void)addTimerToRunLoop {
    
    if (self.timer ==  nil) {
        
        // scheduledTimerWithTimeInterval 这种方式
        // 创建的 Timer 会默认加入到当前的 RunLoop 的 NSDefaultRunLoopMode 中
        self.timer = [NSTimer scheduledTimerWithTimeInterval:2
                                                      target:self
                                                    selector:@selector(runTimer)
                                                    userInfo:nil
                                                     repeats:YES];
    }
}

- (void)runTimer {
    NSLog(@"我是Timer,一直在run方法");
}

UITableView中的大图加载

//添加runloop监听者
- (void)addRunloopObserver {
    
    //    获取 当前的Runloop ref - 指针
    CFRunLoopRef current =  CFRunLoopGetCurrent();
    
    //上下文
    CFRunLoopObserverContext context = {
        0,
        (__bridge void *)(self),
        &CFRetain,
        &CFRelease,
        NULL
    };
    
    //定义一个RunloopObserver
    CFRunLoopObserverRef defaultModeObserver;
    //    创建观察者
    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];
    }
}
//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];
    }
}

监控应用卡顿

参考资料

www.jianshu.com/p/e9b4fafcb… www.jianshu.com/p/fa8bdff45… www.cnblogs.com/qiyiyifan/p…