RunLoop

RunLoop与线程Day19

  • 每条线程都有唯一的一个与之对应的RunLoop对象
  • RunLoop保存在一个全局的Dictionary里,线程作为key,RunLoop作为value
  • 线程刚创建时并没有RunLoop对象,RunLoop会在第一次获取它时创建
  • RunLoop会在线程结束时销毁
  • 主线程的RunLoop已经自动获取(创建),子线程默认没有开启RunLoop

获取RunLoop对象

  • [NSRunLoop currentRunLoop]; // 获得当前线程的RunLoop对象
  • [NSRunLoop mainRunLoop]; // 获得主线程的RunLoop对象
  • CFRunLoopGetCurrent(); // 获得当前线程的RunLoop对象
  • CFRunLoopGetMain(); // 获得主线程的RunLoop对象

RunLoop相关类

image.png

CFRunLoopModeRef

  • CFRunLoopModeRef代表RunLoop的运行模式
  • 一个RunLoop包含若干个Mode,每个Mode又包含若干个Source0/Source1/Timer/Observer
  • RunLoop启动时只能选择其中一个Mode,作为currentMode
  • 如果需要切换Mode,只能退出当前Loop,再重新选择一个Mode进入
  • 不同组的Source0/Source1/Timer/Observer能分隔开来,互不影响
  • 如果Mode里没有任何Source0/Source1/Timer/Observer,RunLoop会立马退出

CFRunLoopModeRef

  • kCFRunLoopDefaultMode(NSDefaultRunLoopMode):App的默认Mode,通常主线程是在这个Mode下运行
  • UITrackingRunLoopMode:界面跟踪 Mode,用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode 影响

CFRunLoopObserverRef

image.png

添加Observer监听RunLoop的所有状态

image.png

RunLoop的运行逻辑

Source0
触摸事件处理
performSelector:onThread:

Source1
基于Port的线程间通信
系统事件捕捉

Timers
NSTimer
performSelector:withObject:afterDelay:

Observers
用于监听RunLoop的状态
UI刷新(BeforeWaiting)
Autorelease pool(BeforeWaiting)

01、通知Observers:进入Loop
02、通知Observers:即将处理Timers
03、通知Observers:即将处理Sources
04、处理Blocks
05、处理Source0(可能会再次处理Blocks)
06、如果存在Source1,就跳转到第8步
07、通知Observers:开始休眠(等待消息唤醒)
08、通知Observers:结束休眠(被某个消息唤醒)
01> 处理Timer
02> 处理GCD Async To Main Queue
03> 处理Source1
09、处理Blocks
10、根据前面的执行结果,决定如何操作
01> 回到第02步
02> 退出Loop
11、通知Observers:退出Loop


image.png

解决NSTimer在不同模式下失效问题

 static int count = 0;
    [NSTimer scheduledTimerWithTimeInterval:1.0 repeats:YES block:^(NSTimer * _Nonnull timer) {
        NSLog(@"%d",++count);
    }];

如上代码是将NSTimer添加到default模式下.当垂涎滑动操作时,RunLoop会切换到UITrackingRunLoopMode模式下,所以NSTimer会失效.

 static int count = 0;
   NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 repeats:YES block:^(NSTimer * _Nonnull timer) {
        NSLog(@"%d",count);
   }];
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
    

NSRunLoopCommonModeskCFRunLoopDefaultModeUITrackingRunLoopMode模式下都可正常运行.NSRunLoopCommonModes不是一个真正的模式,只是一个标记.kCFRunLoopDefaultModeUITrackingRunLoopMode都被默认标记为NSRunLoopCommonModes

线程保活

typedef void (^LDPermenantThreadTask)(void);

@interface LDPermenantThread : NSObject
/**
 开启线程
 */
//- (void)run;

/**
 在当前子线程执行一个任务
 */
- (void)executeTask:(LDPermenantThreadTask)task;

/**
 结束线程
 */
- (void)stop;

@end
#import "LDPermenantThread.h"
/** LDThread **/
@interface LDThread : NSThread
@end
@implementation LDThread
- (void)dealloc
{
    NSLog(@"%s", __func__);
}
@end


@interface LDPermenantThread ()
@property (strong, nonatomic) LDThread *innerThread;
@end
@implementation LDPermenantThread
#pragma mark - public methods
- (instancetype)init
{
    if (self = [super init]) {
        self.innerThread = [[LDThread alloc] initWithBlock:^{
            NSLog(@"begin----");
            
            // 创建上下文(要初始化一下结构体)
            CFRunLoopSourceContext context = {0};
            
            // 创建source
            CFRunLoopSourceRef source = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context);
            
            // 往Runloop中添加source
            CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
            
            // 销毁source
            CFRelease(source);
            
            // 启动
            CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1.0e10, false);
            
            //            while (weakSelf && !weakSelf.isStopped) {
            //                // 第3个参数:returnAfterSourceHandled,设置为true,代表执行完source后就会退出当前loop
            //                CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1.0e10, true);
            //            }
            
            NSLog(@"end----");
        }];
        
        [self.innerThread start];
    }
    return self;
}

//- (void)run
//{
//    if (!self.innerThread) return;
//
//    [self.innerThread start];
//}

- (void)executeTask:(LDPermenantThreadTask)task
{
    if (!self.innerThread || !task) return;
    
    [self performSelector:@selector(__executeTask:) onThread:self.innerThread withObject:task waitUntilDone:NO];
}

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

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

#pragma mark - private methods
- (void)__stop
{
    CFRunLoopStop(CFRunLoopGetCurrent());
    self.innerThread = nil;
}

- (void)__executeTask:(LDPermenantThreadTask)task
{
    task();
}
@end

//使用
#import "ViewController.h"
#import "LDPermenantThread.h"
@interface ViewController ()
@property (strong, nonatomic) LDPermenantThread *thread;
@end

@implementation ViewController
    
- (void)viewDidLoad {
    [super viewDidLoad];
 
    self.thread = [[LDPermenantThread alloc] init];

}
- (IBAction)stop:(id)sender {
    [self.thread stop];

}


- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [self.thread executeTask:^{
        NSLog(@"执行任务 - %@", [NSThread currentThread]);
    }];
    
   
}



@end

你可能感兴趣的:(RunLoop)