PerformSelector 和多线程的关系

PerformSelector 相关

- (id)performSelector:(SEL)aSelector;
- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;

 这三个方法是同步在当前线程执行的。会阻塞当前线程。可在主线程或者子线程执行。
比如

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self performSelector:@selector(doSomething:) withObject:@"111"];
    NSLog(@"over");
}

- (void)doSomething:(NSString *)aStr {
    NSLog(@"doSomething:__%@__, currentThread = %@", aStr, [NSThread currentThread]);
    sleep(2);
    NSLog(@"doSomething sleep over");
}

打印结果是

doSomething:__111__, currentThread = <NSThread: 0x7fe18c904ac0>{number = 1, name = main}
(2s later...)
doSomething sleep over
over

如果在子线程里做会立即打印 over。子线程嘛,当然不会阻塞主线程。


PerformSelector:afterDelay 相关

- (void)performSelector:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay;
- (void)performSelector:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay inModes:(NSArray<NSString *> *)modes;

这两个方法类似,只是第二个方法里指定了线程中 Runloop 的 Modes,这个先不说。
这个方法是异步的,而且只能在主线程中执行。什么意思呢?

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self performSelector:@selector(doSomething:) withObject:@"ahahaha" afterDelay:0];
    NSLog(@"before sleep");
    sleep(4);
    NSLog(@"after sleep");
}

- (void)doSomething:(NSString *)aStr {
    NSLog(@"doSomething:__%@__, currentThread = %@", aStr, [NSThread currentThread]);
}

打印结果是

before sleep
(4s later...)
after sleep
doSomething:__ahahaha__, currentThread = <NSThread: 0x7fdf73706c70>{number = 1, name = main}

能看出来,这个方法不会阻塞当前线程,而是把 Selector 加到主队列里,当 delay 之后执行 Selector。如果主线程在执行业务,那只能等到执行完所有业务之后才会去执行 Selector,就算 delay 等于 0。
那 delay 从什么时候开始计算呢?从 performSelector 的时候。就算这时主线程在阻塞也会计算时间,当阻塞结束之后,如果到了 delay 那就执行 Selector,如果没到就继续 delay。

PerformSelectorOnMainThread 相关

- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray<NSString *> *)array;
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait;
// 相关的指定线程方法就不提了。一个意思。

这俩方法意思很明确,可以在主或者子线程中执行,但 Selector 肯定是在主线程中执行。这里只提一下 waitUntilDone。

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self performSelectorOnMainThread:@selector(doSomething:) withObject:@"1111" waitUntilDone:YES];
    NSLog(@"before sleep");
    sleep(2);
    NSLog(@"after sleep");
}

- (void)doSomething:(NSString *)aStr {
    NSLog(@"doSomething:__%@__, currentThread = %@", aStr, [NSThread currentThread]);
    sleep(2);
    NSLog(@"doSomething sleep over");
}

打印结果是

doSomething:__1111__, currentThread = <NSThread: 0x7fc90b5038b0>{number = 1, name = main}
(2s later...)
doSomething sleep over
before sleep
(2s later);
after sleep

很明显,waitUntilDone == YES 会阻塞当前线程,当主线程执行完 Selector 之后才会继续执行当前线程。如果是 NO 呢?

before sleep
(2s later...)
after sleep
doSomething:__1111__, currentThread = <NSThread: 0x7fc90b5038b0>{number = 1, name = main}
(2s later);
doSomething sleep over

主线程不会阻塞当前线程,大家互不干扰。但上述代码中的当前线程是主线程,那么和 performSelector:afterDelay 类似,主线程顺序执行完业务之后才会继续执行 Selector 的业务。如果当前线程是子线程呢?

- (void)viewDidLoad {
    [super viewDidLoad];
    
    dispatch_queue_t t1 = dispatch_queue_create("sub queue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(t1, ^{
        [self performSelectorOnMainThread:@selector(doSomething:) withObject:@"1111" waitUntilDone:NO];
        NSLog(@"before sleep");
        sleep(2);
        NSLog(@"after sleep");
    });
}

- (void)doSomething:(NSString *)aStr {
    NSLog(@"doSomething:__%@__, currentThread = %@", aStr, [NSThread currentThread]);
    sleep(2);
    NSLog(@"doSomething sleep over");
}

打印结果是

before sleep
doSomething:__1111__, currentThread = <NSThread: 0x7ff7c2603a00>{number = 1, name = main}
(after 2s...)
after sleep
doSomething sleep over

当前线程和主线程互不干扰,大家是并行的。那如果 waitUntilDone == YES 呢?
当然是等主线程执行完之后再接着执行子线程里的业务了。

doSomething:__1111__, currentThread = <NSThread: 0x7fd3a1f03510>{number = 1, name = main}
(2s later...)
doSomething sleep over
before sleep
(2s later...)
after sleep

大致就是这样。


原文链接:https://www.jianshu.com/p/0d16da7ec609

猜你喜欢

转载自blog.csdn.net/sinat_32283541/article/details/86083764