Runloop

作者: 咔咔尼亜 | 来源:发表于2019-07-12 13:17 被阅读0次

    RunLoop详解

    runloop的本质是一个对象,这个对象有一个入口函数,执行入口函数之后就会进入一个do while循环,循环的处理一些事情。

    没有runloop的情况下,程序运行完成就会退出。
    有runloop的时候程序运行完成的时候不会退出

    runloop的作用

    1. 保持程序持续运行
    2. 处理app中的各种事件(触摸、定时器、performselector等)
    3. 节省cpu资源,提高程序性能(有事件的饿时候处理事件,没事件的时候休息,可以在main函数中直接返回1进行测试)

    线程和runloop

    1. 线程和runloop是一一对应的关系(内部是一个字典,key为线程,value为runloop)
    2. 线程创建的时候,并没有创建runloop对象,runloop会在第一次获取的时候自动创建
    3. 主线程默认开启了runloop,子线程默认没有开启runloop

    runloop的mode

    1. 一个runloop对应一个线程
    2. 一个runloop包含多个mode,每个mode包含若干个source、timer、observer
    3. source、timer、observer又叫modeitem,不同的mode下mode item 互不影响
    4. runloop运行过程中,只会选择一种模式运行
    5. 切换mode,程序退出当前mode,再重新制定mode执行

    ModeItem

    source0事件
    1. 触摸事件
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
    {
        NSLog(@"testRunloop"); //打断点可以看到堆栈信息中 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__
    }
    
    1. 自定义输入园source0
    - (void)testAction:(UIButton *)sender
    {
        NSThread *subThread = [[NSThread alloc]initWithBlock:^{
            CFRunLoopSourceContext context = {
                0,
                NULL,
                NULL,
                NULL,
                NULL,
                NULL,
                NULL,
                schedule,
                cancel,
                perform
            };
            CFRunLoopSourceRef source0 = CFRunLoopSourceCreate(CFAllocatorGetDefault(), 0, &context);
            //有下面一行才能触发schedule回调
            CFRunLoopAddSource(CFRunLoopGetCurrent(), source0, kCFRunLoopDefaultMode);
            
            //有以下代码才能触发perform回调
            CFRunLoopSourceSignal(source0);
            CFRunLoopWakeUp(CFRunLoopGetCurrent());
            //触发cancel回调
            CFRunLoopRemoveSource(CFRunLoopGetCurrent(), source0, kCFRunLoopDefaultMode);
            CFRelease(source0); //释放
        }];
        [subThread start];
    }
    void schedule(void *info, CFRunLoopRef rl, CFRunLoopMode mode)
    {
        NSLog(@"currentThreed ===%s",__func__);
    }
    
    void cancel(void *info, CFRunLoopRef rl, CFRunLoopMode mode)
    {
        NSLog(@"currentThreedMode ===%s",__func__);
    }
    
    void perform(void *info)
    {
      NSLog(@"currentThreedInfo ===%s",__func__);
    }
    
    1. performSelector:onThread:方法调用
    [self performSelectorOnMainThread:@selector(animation:) withObject:nil waitUntilDone:NO];
    - (void)animation:(id)sender
    {
        NSLog(@"哈哈"); //此处打断点可以在堆栈中看到 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__
    }
    
    source1
    1. 端口(NSPort)----

    注意测试代码在模拟器上控制台能打印出来在手机上不行,原因是通过NSPort的port类方法创建出来的是它的子类对象NSMachPort,而Foundation框架给我们提供的NSPort的三个子类中NSMachPort和NSMessagePort只能用于同一台机器上的通信,NSSocketPort可以用于本地和远程通信。

    - (void)viewDidLoad
    {
        [super viewDidLoad];
        self.mainPort = [NSPort port];
        self.mainPort.delegate = self;
        [[NSRunLoop currentRunLoop] addPort:self.mainPort forMode:NSDefaultRunLoopMode];
    
        NSThread *testThread = [[NSThread alloc]initWithBlock:^{
            self.subPort = [NSPort port];
            self.subPort.delegate = self;
            [[NSRunLoop currentRunLoop] addPort:self.subPort forMode:NSDefaultRunLoopMode];
            [[NSRunLoop currentRunLoop] run];
        }];
        [testThread setName:@"subThread"];
        [testThread start];
    }
    
    - (IBAction)testAction:(UIButton *)sender
    {
        NSMutableArray *conmponents = [NSMutableArray array];
        [conmponents addObject:[@"fromMainThread" dataUsingEncoding:NSUTF8StringEncoding]];
        [self.subPort sendBeforeDate:[NSDate date] components:conmponents from:self.mainPort reserved:0];
    }
    
    - (void)handlePortMessage:(id)message
    {
        NSMutableArray *array = [message valueForKey:@"components"]; //此处打断点可以在堆栈中看到__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__说明这是一个source1源
        NSString *password = [[NSString alloc]initWithData:[array  firstObject] encoding:NSUTF8StringEncoding];
        NSLog(@"thread ===%@\tpassword===%@", [NSThread currentThread], password);
        if (![[NSThread currentThread] isMainThread]) {
            NSMutableArray *conmponents = [NSMutableArray array];
            [conmponents addObject:[@"fromSubthread" dataUsingEncoding:NSUTF8StringEncoding]];
            [self.mainPort sendBeforeDate:[NSDate date] components:conmponents from:self.subPort reserved:0];
        }
    }
    
    计时源
    1. NStimer
    2. performSelector:withObject:afterDelay
    [self performSelector:@selector(animation:) withObject:nil afterDelay:3];
    - (void)animation:(id)sender
    {
        NSLog(@"哈哈"); //此处打断点可以在堆栈中看到 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__
    }
    

    相关文章

      网友评论

          本文标题:Runloop

          本文链接:https://www.haomeiwen.com/subject/bgyekctx.html