iOS RunLoop实际使用场景汇总

133 阅读1分钟
  1. 线程保活(参考YYWebImageOperation
/// Network thread entry point.
+ (void)_networkThreadMain:(id)object {
    @autoreleasepool {
        [[NSThread currentThread] setName:@"com.ibireme.yykit.webimage.request"];
        NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
        [runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
        [runLoop run];
    }
}

/// Global image request network thread, used by NSURLConnection delegate.
+ (NSThread *)_networkThread {
    static NSThread *thread = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        thread = [[NSThread alloc] initWithTarget:self selector:@selector(_networkThreadMain:) object:nil];
        if ([thread respondsToSelector:@selector(setQualityOfService:)]) {
            thread.qualityOfService = NSQualityOfServiceBackground;
        }
        [thread start];
    });
    return thread;
}
  1. 监测卡顿
- (void)beginMonitor {
    _semaphore = dispatch_semaphore_create(0);
    
    CFRunLoopObserverContext context = {0, (__bridge void *)self, NULL, NULL, NULL};
    _observer = CFRunLoopObserverCreate(kCFAllocatorDefault, kCFRunLoopAllActivities, true, 0, myCFRunLoopObserverCallBack, &context);
    CFRunLoopAddObserver(CFRunLoopGetMain(), _observer, kCFRunLoopCommonModes);
    
    dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{
        while (1) {
            intptr_t result = dispatch_semaphore_wait(self->_semaphore, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_MSEC * 20));
            if (result != 0) {
                if (!self->_observer) {
                    self->_semaphore = 0;
                    self->_activity = 0;
                    self->_timeoutCount = 0;
                    return;
                }
                // 为什么是监测kCFRunLoopBeforeSources和kCFRunLoopAfterWaiting这两种状态?因为:
                // 1、source1和timer都是在kCFRunLoopAfterWaiting之后执行
                // 2、source0是在kCFRunLoopBeforeSources之后执行
                // 3、source0和source1同时存在时,在kCFRunLoopBeforeSources之后先执行source0再执行source1
                if (self->_activity == kCFRunLoopBeforeSources || self->_activity == kCFRunLoopAfterWaiting) {
                    if (++self->_timeoutCount < 3) { // count从1开始比较,count=3时执行下面语句,正好三次
                        continue;
                    }
                    // TODO: 卡顿上报
                }
            }
            self->_timeoutCount = 0;
        }
    });
}

void myCFRunLoopObserverCallBack(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info) {
    ViewController *vc = (__bridge ViewController *)info;
    vc->_activity = activity;
    dispatch_semaphore_signal(vc->_semaphore);
}
  1. 性能优化(参考YYTransaction
static void YYTransactionSetup() {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        transactionSet = [NSMutableSet new];
        CFRunLoopRef runloop = CFRunLoopGetMain();
        CFRunLoopObserverRef observer;
        
        observer = CFRunLoopObserverCreate(CFAllocatorGetDefault(),
                                           kCFRunLoopBeforeWaiting | kCFRunLoopExit,
                                           true,      // repeat
                                           0xFFFFFF,  // after CATransaction(2000000)
                                           YYRunLoopObserverCallBack, NULL);
        CFRunLoopAddObserver(runloop, observer, kCFRunLoopCommonModes);
        CFRelease(observer);
    });
}
  1. UITableView滑动优化
// tableView滑动停止才会执行
[self performSelector:@selector(setCellImage:) withObject:cell afterDelay:0 inModes:@[NSDefaultRunLoopMode]];

- (void)setCellImage:(MyTableViewCell *)cell {
    NSString *path = [[NSBundle mainBundle] pathForResource:@"mypic" ofType:@"jpg"];
    cell.imgView.image = [UIImage imageWithContentsOfFile:path];
}
  1. crash防护
CFRunLoopRef runLoop = CFRunLoopGetCurrent();
CFArrayRef allModes = CFRunLoopCopyAllModes(runLoop);

while (true) {
    for (NSString *mode in (__bridge NSArray *)allModes) {
        CFRunLoopRunInMode((CFStringRef)mode, 0.001, false);
    }
}

未完待续。。。