performSelector不执行,主线程和子线程的调用

问题一(在主线程中执行)

先看一段代码


- (void)viewDidLoad {
    [super viewDidLoad];
    dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"1");
        [self performSelector:@selector(printLog) withObject:nil afterDelay:1];
        NSLog(@"3");
        ;
    });
}

- (void)printLog {
    NSLog(@"2");
}

这段代码的 log 是什么呢,我想大家都知道了

2018-05-27 21:14:38.753695+0800 aaa[44666:6677653] 1
2018-05-27 21:14:38.753910+0800 aaa[44666:6677653] 3
2018-05-27 21:14:39.754311+0800 aaa[44666:6677653] 2

那么这样呢,

- (void)viewDidLoad {
    [super viewDidLoad];
    dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"1");
        [self performSelector:@selector(printLog) withObject:nil afterDelay:0];
        NSLog(@"3");
        ;
    });
}

- (void)printLog {
    NSLog(@"2");
}

我想很多人可能会说 123,因为延迟写的是0去,而结果呢。


2018-05-27 21:15:42.140890+0800 aaa[44727:6679619] 1
2018-05-27 21:15:42.141121+0800 aaa[44727:6679619] 3
2018-05-27 21:15:42.142397+0800 aaa[44727:6679619] 2

在看一个

- (void)viewDidLoad {
    [super viewDidLoad];
    dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"1");
        [self performSelector:@selector(printLog) withObject:nil afterDelay:0];
        sleep(2);
        NSLog(@"3");
        ;
    });
}

- (void)printLog {
    NSLog(@"2");
}

这次的结果又是什么呢,我想可能也有好多人会说123,那么答案呢

2018-05-27 21:16:33.261381+0800 aaa[44775:6681215] 1
2018-05-27 21:16:35.261782+0800 aaa[44775:6681215] 3
2018-05-27 21:16:35.263039+0800 aaa[44775:6681215] 2

由此可见 这个方法异步执行的,不会阻塞当前的线程,会等待主线程的任务执行完成之后才回去执行

而换成这样呢


- (void)viewDidLoad {
    [super viewDidLoad];
    dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"1");
        [self performSelector:@selector(printLog) withObject:nil ];
        sleep(2);
        NSLog(@"3");
        ;
    });
}

- (void)printLog {
    NSLog(@"2");
}

答案是123,可见这个方法是同步=执行的会阻塞当前的线程。

问题二(在子线程中执行)

再看一段代码,将主线程改为子线程


- (void)viewDidLoad {
    [super viewDidLoad];
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"1");
        [self performSelector:@selector(printLog) withObject:nil ];
        sleep(2);
        NSLog(@"3");
        ;
    });
}

- (void)printLog {
    NSLog(@"2");
}

可见结果是123,证明这个方法是同步执行的,与线程无关

在看一个

- (void)viewDidLoad {
    [super viewDidLoad];
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"1");
        [self performSelector:@selector(printLog) withObject:nil afterDelay:0];
        NSLog(@"3");
        ;
    });
}

- (void)printLog {
    NSLog(@"2");
}

答案是什么呢,说到答案,有很多人肯定就蒙了,

2018-05-27 21:21:31.217771+0800 aaa[45008:6689138] 1
2018-05-27 21:21:31.218179+0800 aaa[45008:6689138] 3

方法没有执行,为什么呢,performSelector 是需要提交到runloop上面去执行的,GCD底层分派的线程是没有开启runloop能力的,也就是说在子线程中,runloop默认是没有开启的,说到 nstimer 大家就一定会明白,我们在自现场建立一个nstimer,是需要run起来的,这个和那个是一样的道理,因为 子线程的runloop没有开启,所以方法没有执行.

改为这样呢

- (void)viewDidLoad {
    [super viewDidLoad];
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"1");
        [self performSelector:@selector(printLog) withObject:nil afterDelay:2];
        [[NSRunLoop currentRunLoop] run];
        NSLog(@"3");
        ;
        
    });
}

- (void)printLog {
    NSLog(@"2");
}

答案是


2018-05-27 21:26:25.654391+0800 aaa[45232:6696585] 1
2018-05-27 21:26:27.658696+0800 aaa[45232:6696585] 2
2018-05-27 21:26:27.658891+0800 aaa[45232:6696585] 3

当开启runloop后,会立刻去执行runloop的操作,等待执行完毕后,继续向下执行,runloop的开启位置很重要,决定了,代码的执行顺序,比如我们这样,

- (void)viewDidLoad {
    [super viewDidLoad];
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"1");
        [self performSelector:@selector(printLog) withObject:nil afterDelay:2];
        
        NSLog(@"3");
        ;
        [[NSRunLoop currentRunLoop] run];
        
    });
}

- (void)printLog {
    NSLog(@"2");
}

答案是


2018-05-27 21:28:23.793809+0800 aaa[45328:6699868] 1
2018-05-27 21:28:23.794209+0800 aaa[45328:6699868] 3
2018-05-27 21:28:25.799013+0800 aaa[45328:6699868] 2

开启的是当前子线程的runloop,其余代码征程执行,当开启的时候,会立刻执行runloop的操作,是不是很神奇。

总结

我看到网上有人说,performSelector 只能在主线程上面执行,这种说法是错误的,是可以在子线程中执行的,需要开启当前线程的 runloop,有可能我上面的解释不对,如果有不对的,一定要给我评论,纠正我,共同进步,谢谢!

你可能感兴趣的:(performSelector不执行,主线程和子线程的调用)