08 - 多线程 - 03:performSelector:withObject:afterDelay:方法

总结

  1. 面试题:在 GCD 中调用 performSelector:withObject:afterDelay: 方法,打印结果是什么?
  2. performSelector:withObject:afterDelay: 方法 和 performSelector:withObject: 方法 的区别

面试题:

面试题:在 GCD 中调用 performSelector:withObject:afterDelay: 方法,打印结果是什么?

// 全局并发队列
dispatch_queue_t queue = dispatch_Get_global_queue(0,0);
// 异步任务  
dispatch_async(queue, ^{
	NSLog(@"1");
	[self performSelector:@selector(test) withObject:nil afterDelay: .0];
	NSLog(@"3");
});

- (void) test {
	NSLog(@"2");
}
  • 打印结果是:1、3
  • 为什么没有打印2?原因:
    • performSelector:withObject:afterDelay:的本质是往Runloop中添加定时器
    • 而子线程默认没有启动Runloop

一、方法的含义

    [self performSelector:@selector(test) withObject:nil afterDelay:3.0];
  • 含义:三秒以后,调用 self的 test 方法
  • afterDelay 后面 可以写 “.0” :表示 0秒以后执行 self的 test 方法

二、performSelector:withObject:afterDelay: 方法

  1. GCD 中写 performSelector:withObject:afterDelay: 方法
 dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    
    dispatch_async(queue, ^{
        NSLog(@"1");
        [self performSelector:@selector(test) withObject:nil afterDelay:0.0];
        NSLog(@"3");
    });

打印结果:
1
3

test 没有 被调用。

  1. 在主线程中 调用此方法
- (void)viewDidLoad {
    [super viewDidLoad];
    
    NSLog(@"1");
    [self performSelector:@selector(test) withObject:nil afterDelay:0.3];
    NSLog(@"3");
}

打印结果:
1
3
2

  1. performSelector:withObject:afterDelay: 的底层
  • 不在 NSObject 中,而是在NSRunLoop 类中
  • 带有 afterDelay 的方法,都是在 NSRunLoop 类中定义的
  1. 为何在 主线程就可以调用 test 方法,在GCD 中却不能调用 test 方法?
  • 这是因为 performSelector:withObject:afterDelay: 类的底层调用了 NSTimer 定时器。
  • 定时器是要添加到 runloop 中去的。
  • 这句话的底层就是 往 runloop 中添加了一个定时器。
  • 主线程 默认有 runloop,所以 在主线程 可以调用 test方法。
  • 而 GCD 中没有 runloop ,所以 不会调用 test 方法。如果想要在 GCD 中调用 test 方法,需要自己开启 runloop 。

完整代码:
08 - 多线程 - 03:performSelector:withObject:afterDelay:方法_第1张图片
打印结果:
1
3
2


三、performSelector:withObject: 方法

  1. 在 GCD 中调用 此方法
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    
    dispatch_async(queue, ^{
        NSLog(@"1");
        [self performSelector:@selector(test) withObject:nil];
        NSLog(@"3");
    });
    

打印结果:
1
2
3

  1. performSelector:withObject: 的底层代码
    在这里插入图片描述
  • performSelector:withObject: 是在 NSObject 中定义的;
  • [self performSelector:@selector(test) withObject:nil] 会在底层转换为 objcMsgSend(self, @selector(test)).

四、GNUstep

  • 因为 runloop 的底层看不到,所以可以 看第三方写的OC 库。这就是 GNUstep
    源码址:
  • http://www.gnustep.org/resources/downloads.php

五、了解 GNUstep 中 performSelector:withObject:afterDelay: 的底层

  • base项目 -> source 文件夹 -> Foundation 文件夹 -> NSRunLoop.m

  • 找到 performSelector:withObject:afterDelay: 方法
    08 - 多线程 - 03:performSelector:withObject:afterDelay:方法_第2张图片

    • 创建一个 runloop
    • 创建一个 time
    • 把 time 添加到 runloop 中
  • initWithSelector: target: argument: delay: 方法
    08 - 多线程 - 03:performSelector:withObject:afterDelay:方法_第3张图片

这里面 只有创建 runloop ,没有启动runloop ,所以需要自己启动runloop。

你可能感兴趣的:(iOS底层)