performSelector
1 2 3 4 5 6 7 8 9 10
| //在当前线程延迟1s执行,响应了OC语言的动态性:延迟到运行时才绑定方法 [self performSelector:@selector(aaa) withObject:nil afterDelay:1]; // 回到主线程,waitUntilDone:是否将该回调方法执行完再执行后面的代码 // 如果为YES:就必须等回调方法执行完成之后才能执行后面的代码,说白了就是阻塞当前的线程 // 如果是NO:就是不等回调方法结束,不会阻塞当前线程 [self performSelectorOnMainThread:@selector(aaa) withObject:nil waitUntilDone:YES]; // 开辟子线程 [self performSelectorInBackground:@selector(aaa) withObject:nil]; //在指定线程执行 [self performSelector:@selector(aaa) onThread:[NSThread currentThread] withObject:nil waitUntilDone:YES];
|
- 需要注意的是:如果是带
afterDelay
的延时函数,会在内部创建一个NSTimer
,然后添加到当前线程的Runloop
中。也就是如果当前线程没有开启runloop
,该方法会失效。在子线程中,需要启动runloop
(注意调用顺序)1 2
| [self performSelector:@selector(aaa) withObject:nil afterDelay:1]; [[NSRunLoop currentRunLoop] run];
|
performSelector:withObject:
只是一个单纯的消息发送,和时间没有一点关系。所以不需要添加到子线程的Runloop
中也能执行
- 下面代码片段的
test
方法会去执行吗?1 2 3
| dispatch_async(dispatch_get_global_queue(0, 0), ^{ [self performSelector:@selector(test:) withObject:nil afterDelay:0]; });
|
这里的test
方法是不会去执行的,原因在于- (void)performSelector: withObject: afterDelay:
这个方法要创建提交任务到runloop
上的,而gcd
底层创建的线程是默认没有开启对应runloop
的,所有这个方法就会失效。
而如果将dispatch_get_global_queue
改成主队列,由于主队列所在的主线程是默认开启了runloop
的,就会去执行(将dispatch_async
改成同步,因为同步是在当前线程执行,那么如果当前线程是主线程,test
方法也是会去执行的)
- 死锁
- 死锁就是队列引起的循环等待,一个比较常见的死锁例子:主队列同步
1 2 3 4 5 6
| - (void)viewDidLoad { [super viewDidLoad]; dispatch_sync(dispatch_get_main_queue(), ^{ NSLog(@"deallock"); }); }
|
- 在主线程中运用主队列同步,也就是把任务放到了主线程的队列中。同步对于任务是立刻执行的,那么当把任务放进主队列时,它就会立马执行,只有执行完这个任务,
viewDidLoad
才会继续向下执行。而viewDidLoad
和任务都是在主队列上的,由于队列的先进先出
原则,任务又需等待viewDidLoad
执行完毕后才能继续执行,viewDidLoad
和这个任务就形成了相互循环等待,就造成了死锁。
想避免这种死锁,可以将同步改成异步dispatch_async
或者将dispatch_get_main_queue
换成其他串行或并行队列,都可以解决
- 同样,下边的代码也会造成死锁:
1 2 3 4 5 6
| dispatch_queue_t serialQueue = dispatch_queue_create("test", DISPATCH_QUEUE_SERIAL); dispatch_async(serialQueue, ^{ dispatch_sync(serialQueue, ^{ NSLog(@"deadlock"); }); });
|
- 外面的函数无论是同步还是异步都会造成死锁。这是因为里面的任务和外面的任务都在同一个
serialQueue
队列内,又是同步,这就和上边主队列同步的例子一样造成了死锁。
解决方法也和上边一样,将里面的同步改成异步dispatch_async
或者将serialQueue
换成其他串行或并行队列,都可以解决
-------------本文结束感谢您的阅读-------------