多執行緒二:performSelector:withObject:afterDelay:方法
阿新 • • 發佈:2018-11-07
面試題:
列印結果是:1、3
原因
performSelector:withObject:afterDelay:的本質是往Runloop中新增定時器
子執行緒預設沒有啟動Runloop
一、方法的含義
[self performSelector:@selector(test) withObject:nil afterDelay:3.0];
- 含義:三秒以後,呼叫 self的 test 方法
- afterDelay 後面 可以寫 “.0” :表示 0秒以後執行 self的 test 方法
二、performSelector:withObject:afterDelay: 方法
- 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 沒有 被呼叫。
- 在主執行緒中 呼叫此方法
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"1");
[self performSelector:@selector(test) withObject:nil afterDelay:0.3];
NSLog(@"3");
}
列印結果:
1
3
2
- performSelector:withObject:afterDelay: 的底層
- 不在 NSObject 中,而是在NSRunLoop 類中
- 帶有 afterDelay 的方法,都是在 NSRunLoop 類中定義的
- 為何在 主執行緒就可以呼叫 test 方法,在GCD 中卻不能呼叫 test 方法?
- 這是因為 performSelector:withObject:afterDelay: 類的底層呼叫了 NSTimer 定時器。
- 定時器是要新增到 runloop 中去的。
- 這句話的底層就是 往 runloop 中添加了一個定時器。
- 主執行緒 預設有 runloop,所以 在主執行緒 可以呼叫 test方法。
- 而 GCD 中沒有 runloop ,所以 不會呼叫 test 方法。如果想要在 GCD 中呼叫 test 方法,需要自己開啟 runloop 。
完整程式碼:
列印結果:
1
3
2
三、performSelector:withObject: 方法
- 在 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
- 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: 方法
- 建立一個 runloop
- 建立一個 time
- 把 time 新增到 runloop 中
-
initWithSelector: target: argument: delay: 方法
這裡面 只有建立 runloop ,沒有啟動runloop ,所以需要自己啟動runloop。