IOS底层原理 -6.runloop

1. 简介

iOS 中负责程序运行循环,在程序运行过程中循环做一些事情;保持程序的运行,程序运行时会在main函数中创建一个runloop,负责主线程的持续运行;及处理app中的各种事件的响应,例如:NSTimer,UITouch等;在程序需要处理事件时候runloop就唤起线程,当不许处理事件的时候线程进入休眠状态,这样可以节省线程资源。
在OC中每一个线程都有唯一的一个Runloop对象;Runloop对象保存在一个全局的dictionary里,线程作为键Runloop作为值;线程刚创建的时候是没有runloop,当第一次获取的时候创建;mian线程的Runloop程序运行时已经获取了。

2. Runloop 对象获取

源码可以在苹果开源网站下载,
2.1 get方法
在源码里找到CFRunLoop.c文件,在该文件里搜索 CFRunloopGetCurrent()方法;该方法里调用了_CFRunLoopGet0(pthread_self());,下面看下该方法实现:

CF_EXPORT CFRunLoopRef _CFRunLoopGet0(pthread_t t) {
    if (pthread_equal(t, kNilPthreadT)) {
	t = pthread_main_thread_np();
    }
    __CFLock(&loopsLock);
    if (!__CFRunLoops) {//如果不存在,则创建一个保存Runloop对象的字典,
        __CFUnlock(&loopsLock);
	CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks);
	CFRunLoopRef mainLoop = __CFRunLoopCreate(pthread_main_thread_np());//创建线程的runloop
	CFDictionarySetValue(dict, pthreadPointer(pthread_main_thread_np()), mainLoop);
	if (!OSAtomicCompareAndSwapPtrBarrier(NULL, dict, (void * volatile *)&__CFRunLoops)) {
	    CFRelease(dict);
	}
	CFRelease(mainLoop);
        __CFLock(&loopsLock);
    }
    CFRunLoopRef loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));//从字典里取值
    __CFUnlock(&loopsLock);
    if (!loop) {//如果没有获取到
	CFRunLoopRef newLoop = __CFRunLoopCreate(t);//则创建
        __CFLock(&loopsLock);
	loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));
	if (!loop) {
	    CFDictionarySetValue(__CFRunLoops, pthreadPointer(t), newLoop);
	    loop = newLoop;
	}
        // don't release run loops inside the loopsLock, because CFRunLoopDeallocate may end up taking it
        __CFUnlock(&loopsLock);
	CFRelease(newLoop);
    }
    if (pthread_equal(t, pthread_self())) {
        _CFSetTSD(__CFTSDKeyRunLoop, (void *)loop, NULL);
        if (0 == _CFGetTSD(__CFTSDKeyRunLoopCntr)) {
            _CFSetTSD(__CFTSDKeyRunLoopCntr, (void *)(PTHREAD_DESTRUCTOR_ITERATIONS-1), (void (*)(void *))__CFFinalizeRunLoop);
        }
    }
    return loop;
}

2.2 runLoop 相关类及执行状态
常用相关的类主要有5个:CFRunLoopRef、CFRunLoopModelRef、CFRunLoopSourceRef、CFRunLoopTimerRef、CFRunLoopObseverRef;
CFRunLoop在公开的源码里的实现是:

struct __CFRunLoop {
    CFRuntimeBase _base;
    pthread_t _pthread;
    uint32_t _winthread;
    CFMutableSetRef _commonModes;
    CFMutableSetRef _commonModeItems;
    CFRunLoopModeRef _currentMode;//当前的模式
    CFMutableSetRef _modes;//所有的运行模式
};
struct __CFRunLoopMode {
    CFRuntimeBase _base;
    CFStringRef _name;
    CFMutableSetRef _sources0;//触摸事件,performSelector:onThread:withobject:
    CFMutableSetRef _sources1;
    CFMutableArrayRef _observers;
    CFMutableArrayRef _timers;
    CFMutableDictionaryRef _portToV1SourceMap;
};

从上述源码中,可以看出一个RunLooop可以包含多个mode,每一个mode又包含多个_sources0、_sources1、_observers、_timers;当前是那个mode取决于_currentMode,同时也只能存在一种模式可以作为_currentMode,当需要切换到另外一种模式的时候会退出当前的mode;常用的有两种mode:kCFRunLoopDefaultMode 主线程一般都是运行在该mode下、UITrackingRunLoopMode 界面跟踪mode,界面滑动触摸,保证界面滑动时候不受其他mode的影响;
看一下触摸事件的函数调用堆栈:
在这里插入图片描述
接下来通过一段代码验证一下模式的切换:

  CFRunLoopObserverRef obRef = CFRunLoopObserverCreateWithHandler(kCFAllocatorDefault, kCFRunLoopAllActivities,YES,0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
       
        switch (activity) {
            case kCFRunLoopEntry:{
                CFRunLoopMode mode =  CFRunLoopCopyCurrentMode(CFRunLoopGetCurrent());
                NSLog(@"kCFRunLoopEntry %@",mode);
                CFRelease(mode);
            }
    
                break;
            case kCFRunLoopBeforeTimers: {
                
                break;
            }
            case kCFRunLoopBeforeSources: {
                
                break;
            }
            case kCFRunLoopBeforeWaiting: {
                
                break;
            }
            case kCFRunLoopAfterWaiting: {
                
                break;
            }
            case kCFRunLoopExit: {
                CFRunLoopMode mode =  CFRunLoopCopyCurrentMode(CFRunLoopGetCurrent());
                NSLog(@"kCFRunLoopExit %@",mode);
                CFRelease(mode);
                break;
            }
            case kCFRunLoopAllActivities: {
                
                break;
            }
        }
    });
//  CFRunLoopObserverRef obRef =  CFRunLoopObserverCreate(kCFAllocatorDefault, kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info){
//
//    }, NULL);
    CFRunLoopAddObserver(CFRunLoopGetCurrent(), obRef, kCFRunLoopCommonModes);
    CFRelease(obRef);

滑动view后的输出:
在这里插入图片描述

3. RunLoop 运行逻辑

在这里插入图片描述
以下部分内容来自iOS底层原理总结 - RunLoop

3.1 RunLoop 调用过程

RunLoop 在CoreFoundation框架中可以添加消息监听

    CFRunLoopObserverRef obRef = CFRunLoopObserverCreateWithHandler(kCFAllocatorDefault, kCFRunLoopAllActivities,YES,0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
       
        switch (activity) {
            case kCFRunLoopEntry:{
                CFRunLoopMode mode =  CFRunLoopCopyCurrentMode(CFRunLoopGetCurrent());
                NSLog(@"kCFRunLoopEntry 进入 %@",mode);
                CFRelease(mode);
            }
    
                break;
            case kCFRunLoopBeforeTimers: {
                CFRunLoopMode mode =  CFRunLoopCopyCurrentMode(CFRunLoopGetCurrent());
                NSLog(@"kCFRunLoopBeforeTimers 处理timer %@",mode);
                CFRelease(mode);
                break;
            }
            case kCFRunLoopBeforeSources: {
                CFRunLoopMode mode =  CFRunLoopCopyCurrentMode(CFRunLoopGetCurrent());
                NSLog(@"kCFRunLoopBeforeSources 处理source %@",mode);
                CFRelease(mode);
                break;
            }
            case kCFRunLoopBeforeWaiting: {
                CFRunLoopMode mode =  CFRunLoopCopyCurrentMode(CFRunLoopGetCurrent());
                NSLog(@"kCFRunLoopBeforeWaiting 开始进入休息 %@",mode);
                CFRelease(mode);
                break;
            }
            case kCFRunLoopAfterWaiting: {
                CFRunLoopMode mode =  CFRunLoopCopyCurrentMode(CFRunLoopGetCurrent());
                NSLog(@"kCFRunLoopAfterWaiting 已经恢复 %@",mode);
                CFRelease(mode);
                break;
            }
            case kCFRunLoopExit: {
                CFRunLoopMode mode =  CFRunLoopCopyCurrentMode(CFRunLoopGetCurrent());
                NSLog(@"kCFRunLoopExit 退出了 %@",mode);
                CFRelease(mode);
                break;
            }
            case kCFRunLoopAllActivities: {
                CFRunLoopMode mode =  CFRunLoopCopyCurrentMode(CFRunLoopGetCurrent());
                NSLog(@"kCFRunLoopAllActivities %@",mode);
                CFRelease(mode);
                break;
            }
        }
    });
//  CFRunLoopObserverRef obRef =  CFRunLoopObserverCreate(kCFAllocatorDefault, kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info){
//
//    }, NULL);
    CFRunLoopAddObserver(CFRunLoopGetCurrent(), obRef, kCFRunLoopCommonModes);
    CFRelease(obRef);

控制台输出,部分代码精简:

2019-09-25 09:06:58.969802+0800 testRunLoop[5136:43000] kCFRunLoopBeforeTimers 处理timer kCFRunLoopDefaultMode
2019-09-25 09:06:58.970439+0800 testRunLoop[5136:43000] kCFRunLoopBeforeSources 处理source kCFRunLoopDefaultMode
2019-09-25 09:06:58.970643+0800 testRunLoop[5136:43000] kCFRunLoopBeforeTimers 处理timer kCFRunLoopDefaultMode
2019-09-25 09:06:58.970760+0800 testRunLoop[5136:43000] kCFRunLoopBeforeSources 处理source kCFRunLoopDefaultMode
2019-09-25 09:06:58.970909+0800 testRunLoop[5136:43000] kCFRunLoopBeforeTimers 处理timer kCFRunLoopDefaultMode
2019-09-25 09:09:00.007058+0800 testRunLoop[5136:43000] kCFRunLoopBeforeWaiting 开始进入休息 kCFRunLoopDefaultMode
2019-09-25 09:10:00.003054+0800 testRunLoop[5136:43000] kCFRunLoopAfterWaiting 已经恢复 kCFRunLoopDefaultMode
2019-09-25 09:10:00.006223+0800 testRunLoop[5136:43000] kCFRunLoopBeforeTimers 处理timer kCFRunLoopDefaultMode
2019-09-25 09:10:00.006520+0800 testRunLoop[5136:43000] kCFRunLoopBeforeSources 处理source kCFRunLoopDefaultMode
2019-09-25 09:10:00.006804+0800 testRunLoop[5136:43000] kCFRunLoopBeforeWaiting 开始进入休息 kCFRunLoopDefaultMode
2019-09-25 09:11:00.002788+0800 testRunLoop[5136:43000] kCFRunLoopAfterWaiting 已经恢复 kCFRunLoopDefaultMode
2019-09-25 09:11:00.005685+0800 testRunLoop[5136:43000] kCFRunLoopBeforeTimers 处理timer kCFRunLoopDefaultMode
2019-09-25 09:11:00.005937+0800 testRunLoop[5136:43000] kCFRunLoopBeforeSources 处理source kCFRunLoopDefaultMode
2019-09-25 09:11:00.006132+0800 testRunLoop[5136:43000] kCFRunLoopBeforeWaiting 开始进入休息 kCFRunLoopDefaultMode

3.2 源码简介

// 共外部调用的公开的CFRunLoopRun方法,其内部会调用CFRunLoopRunSpecific
void CFRunLoopRun(void) {   /* DOES CALLOUT */
    int32_t result;
    do {
        result = CFRunLoopRunSpecific(CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 1.0e10, false);
        CHECK_FOR_FORK();
    } while (kCFRunLoopRunStopped != result && kCFRunLoopRunFinished != result);
}

// 经过精简的 CFRunLoopRunSpecific 函数代码,其内部会调用__CFRunLoopRun函数
SInt32 CFRunLoopRunSpecific(CFRunLoopRef rl, CFStringRef modeName, CFTimeInterval seconds, Boolean returnAfterSourceHandled) {     /* DOES CALLOUT */

    // 通知Observers : 进入Loop
    // __CFRunLoopDoObservers内部会调用 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__
函数
    if (currentMode->_observerMask & kCFRunLoopEntry ) __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopEntry);
    
    // 核心的Loop逻辑
    result = __CFRunLoopRun(rl, currentMode, seconds, returnAfterSourceHandled, previousMode);
    
    // 通知Observers : 退出Loop
    if (currentMode->_observerMask & kCFRunLoopExit ) __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopExit);

    return result;
}

// 精简后的 __CFRunLoopRun函数,保留了主要代码
static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInterval seconds, Boolean stopAfterHandle, CFRunLoopModeRef previousMode) {
    int32_t retVal = 0;
    do {
        // 通知Observers:即将处理Timers
        __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeTimers); 
        
        // 通知Observers:即将处理Sources
        __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeSources);
        
        // 处理Blocks
        __CFRunLoopDoBlocks(rl, rlm);
        
        // 处理Sources0
        if (__CFRunLoopDoSources0(rl, rlm, stopAfterHandle)) {
            // 处理Blocks
            __CFRunLoopDoBlocks(rl, rlm);
        }
        
        // 如果有Sources1,就跳转到handle_msg标记处
        if (__CFRunLoopServiceMachPort(dispatchPort, &msg, sizeof(msg_buffer), &livePort, 0, &voucherState, NULL)) {
            goto handle_msg;
        }
        
        // 通知Observers:即将休眠
        __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeWaiting);
        
        // 进入休眠,等待其他消息唤醒
        __CFRunLoopSetSleeping(rl);
        __CFPortSetInsert(dispatchPort, waitSet);
        do {
            __CFRunLoopServiceMachPort(waitSet, &msg, sizeof(msg_buffer), &livePort, poll ? 0 : TIMEOUT_INFINITY, &voucherState, &voucherCopy);
        } while (1);
        
        // 醒来
        __CFPortSetRemove(dispatchPort, waitSet);
        __CFRunLoopUnsetSleeping(rl);
        
        // 通知Observers:已经唤醒
        __CFRunLoopDoObservers(rl, rlm, kCFRunLoopAfterWaiting);
        
    handle_msg: // 看看是谁唤醒了RunLoop,进行相应的处理
        if (被Timer唤醒的) {
            // 处理Timer
            __CFRunLoopDoTimers(rl, rlm, mach_absolute_time());
        }
        else if (被GCD唤醒的) {
            __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__(msg);
        } else { // 被Sources1唤醒的
            __CFRunLoopDoSource1(rl, rlm, rls, msg, msg->msgh_size, &reply);
        }
        
        // 执行Blocks
        __CFRunLoopDoBlocks(rl, rlm);
        
        // 根据之前的执行结果,来决定怎么做,为retVal赋相应的值
        if (sourceHandledThisLoop && stopAfterHandle) {
            retVal = kCFRunLoopRunHandledSource;
        } else if (timeout_context->termTSR < mach_absolute_time()) {
            retVal = kCFRunLoopRunTimedOut;
        } else if (__CFRunLoopIsStopped(rl)) {
            __CFRunLoopUnsetStopped(rl);
            retVal = kCFRunLoopRunStopped;
        } else if (rlm->_stopped) {
            rlm->_stopped = false;
            retVal = kCFRunLoopRunStopped;
        } else if (__CFRunLoopModeIsEmpty(rl, rlm, previousMode)) {
            retVal = kCFRunLoopRunFinished;
        }
        
    } while (0 == retVal);
    
    return retVal;
}

3.3 对timer的影响

    static int timerCount = 0;
    NSTimer *timer = [NSTimer timerWithTimeInterval:1.0f repeats:YES block:^(NSTimer * _Nonnull timer) {
//        NSLog(@"timerCount = %d",self->_timerCount++);
        NSLog(@"timerCount = %d",timerCount++);
    }];
    //NSDefaultRunLoopMode kCFRunLoopCommonModes
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];

在这里插入图片描述
从控制台的时间戳里可以看出,屏幕滑动会对timer的影响;将NSDefaultRunLoopMode换成kCFRunLoopCommonModes屏幕的滑动就不会对timer产生影响;

4 子线程中对NSTimer的影响

4.1 子线程如何使用NSTimer,通过上面的分析知道:主线程runLoop成程序启动后会运行,而子线程的runLoop不主动调用是没有的,而且即使主动调用子线程的runloop是默认不运行的,因此子线程的timer运行,一般我们按照如下方式处理:

#import "TestTimer.h"

@interface TestTimer ()
@property(nonatomic,strong)NSTimer *timer;
@property(nonatomic,strong)dispatch_queue_t que;
@end

@implementation TestTimer
-(void)run{
    static int timerCount = 0;
    self.que = dispatch_queue_create("ddddd", DISPATCH_QUEUE_CONCURRENT);
    __weak typeof(self) weakSelf = self;
    dispatch_async(_que, ^{
         __weak typeof(weakSelf) strongSelf = weakSelf;
        CFRunLoopObserverRef obRef = CFRunLoopObserverCreateWithHandler(kCFAllocatorDefault, kCFRunLoopAllActivities,YES,0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
            
            switch (activity) {
                case kCFRunLoopEntry:{
                    CFRunLoopMode mode =  CFRunLoopCopyCurrentMode(CFRunLoopGetCurrent());
                    NSLog(@"kCFRunLoopEntry 进入 %@",mode);
                    CFRelease(mode);
                }
                    
                    break;
                case kCFRunLoopBeforeTimers: {
                    //                CFRunLoopMode mode =  CFRunLoopCopyCurrentMode(CFRunLoopGetCurrent());
                    //                NSLog(@"kCFRunLoopBeforeTimers 处理timer %@",mode);
                    //                CFRelease(mode);
                    break;
                }
                case kCFRunLoopBeforeSources: {
                    //                CFRunLoopMode mode =  CFRunLoopCopyCurrentMode(CFRunLoopGetCurrent());
                    //                NSLog(@"kCFRunLoopBeforeSources 处理source %@",mode);
                    //                CFRelease(mode);
                    break;
                }
                case kCFRunLoopBeforeWaiting: {
                    //                CFRunLoopMode mode =  CFRunLoopCopyCurrentMode(CFRunLoopGetCurrent());
                    //                NSLog(@"kCFRunLoopBeforeWaiting 开始进入休息 %@",mode);
                    //                CFRelease(mode);
                    break;
                }
                case kCFRunLoopAfterWaiting: {
                    //                CFRunLoopMode mode =  CFRunLoopCopyCurrentMode(CFRunLoopGetCurrent());
                    //                NSLog(@"kCFRunLoopAfterWaiting 已经恢复 %@",mode);
                    //                CFRelease(mode);
                    break;
                }
                case kCFRunLoopExit: {
                    CFRunLoopMode mode =  CFRunLoopCopyCurrentMode(CFRunLoopGetCurrent());
                    NSLog(@"kCFRunLoopExit 退出了 %@",mode);
                    CFRelease(mode);
                    break;
                }
                case kCFRunLoopAllActivities: {
                    CFRunLoopMode mode =  CFRunLoopCopyCurrentMode(CFRunLoopGetCurrent());
                    NSLog(@"kCFRunLoopAllActivities %@",mode);
                    CFRelease(mode);
                    break;
                }
            }
        });
        CFRunLoopAddObserver(CFRunLoopGetCurrent(), obRef, kCFRunLoopCommonModes);
        CFRelease(obRef);
        strongSelf.timer = [NSTimer timerWithTimeInterval:1.0f repeats:YES block:^(NSTimer * _Nonnull timer) {
            //        NSLog(@"timerCount = %d",self->_timerCount++);
            NSLog(@"timerCount = %d",timerCount++);
        }];
        //NSDefaultRunLoopMode UITrackingRunLoopMode NSRunLoopCommonModes
        [[NSRunLoop currentRunLoop] addTimer:strongSelf.timer forMode:NSRunLoopCommonModes];
        [[NSRunLoop currentRunLoop] run];        
    });
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [self.timer invalidate];
    });
}
-(void)dealloc{
    NSLog(@"%s",__func__);
}
@end

运行后输出:

2019-09-25 10:24:05.161121+0800 testRunLoop[19144:159757] kCFRunLoopEntry 进入 kCFRunLoopDefaultMode
2019-09-25 10:24:06.162717+0800 testRunLoop[19144:159757] timerCount = 0
//...省略
2019-09-25 10:24:14.162738+0800 testRunLoop[19144:159757] timerCount = 8
2019-09-25 10:24:15.161226+0800 testRunLoop[19144:159625] -[TestTimer dealloc]

从上面的运行结果发现,runloop在定时器结束后并没有退出循环,如果想在结束后结束子线程循环则需要调用:[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];

2019-09-25 10:28:39.161729+0800 testRunLoop[19809:166720] kCFRunLoopEntry 进入 kCFRunLoopDefaultMode
2019-09-25 10:28:40.165492+0800 testRunLoop[19809:166720] timerCount = 0
//...省略
2019-09-25 10:28:49.162015+0800 testRunLoop[19809:166720] timerCount = 9
2019-09-25 10:28:49.162109+0800 testRunLoop[19809:166667] -[TestTimer dealloc]
2019-09-25 10:28:49.162376+0800 testRunLoop[19809:166720] kCFRunLoopExit 退出了 kCFRunLoopDefaultMode

4. 线程保活

注意:NSRunloop的run方法是无法停止的,一旦掉用该方法就等于开启一个永远不会销毁的线程;及即使调用CFRunloopStop()也只会是停止一次的run;及调用run会无限开启run方法;
看一下实现:

#import "LYMPermemantThread.h"

@interface LYMThread : NSThread

@end

@implementation LYMThread
-(void)dealloc{
    NSLog(@"%s",__func__);
}
@end
@interface LYMPermemantThread ()
@property(nonatomic,strong)LYMThread *innerThred;
@property(nonatomic,assign,getter=isStopped)BOOL stopped;
//@property(nonatomic,copy)void(^innerHandler)(void);
@end

@implementation LYMPermemantThread
- (instancetype)init{
    if (self = [super init]) {
        self.stopped = NO;
        __weak typeof(self) weakSelf = self;
        self.innerThred = [[LYMThread alloc]initWithBlock:^{
            [[NSRunLoop currentRunLoop] addPort:[[NSPort alloc] init] forMode:NSDefaultRunLoopMode];
            
            while (weakSelf && !weakSelf.isStopped) {//一次循环后会退出,这里为防止退出,加入循环在需要退出的时候退出线程
                [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
            }
            
        }];
        [self.innerThred start];
    }
    return self;
}
- (void)run{
//    if (!_innerThred) {
//        return;
//    }
//    [self.innerThred start];
}
- (void)execTaskWithHandler:(void(^)(void))handler{
    if (!_innerThred || !handler) {
        return;
    }
    [self performSelector:@selector(__execBcock:) onThread:self.innerThred withObject:handler waitUntilDone:NO];
}
- (void)stop{
    if (!_innerThred) {
        return;
    }
    [self performSelector:@selector(__stop) onThread:self.innerThred withObject:nil waitUntilDone:YES];
}

- (void) __stop{
    self.stopped = YES;
    CFRunLoopStop(CFRunLoopGetCurrent());
    self.innerThred = nil;
}
- (void)__execBcock:(void(^)(void))handler{
    if (handler) {
        handler();
    }
}
-(void)dealloc{
    NSLog(@"%s",__func__);
    [self stop];
}
@end

使用CF框架实现:

- (instancetype)init{
    if (self = [super init]) {
        self.stopped = NO;
        __weak typeof(self) weakSelf = self;
        self.innerThred = [[LYMThread alloc]initWithBlock:^{
//            [[NSRunLoop currentRunLoop] addPort:[[NSPort alloc] init] forMode:NSDefaultRunLoopMode];
//
//            while (weakSelf && !weakSelf.isStopped) {
//                [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
//            }
            CFRunLoopSourceContext cotext = {0};
            CFRunLoopSourceRef source = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &cotext);
            CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
            CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1.0e10, false);//false 标识source结束后不退出runloop
            
        }];
        [self.innerThred start];
    }
    return self;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

简简单单lym

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值