最近寫一些關於線程保活/取消的測試 具體代碼以下bash
-(void)test {
for (int i = 0; i < 100000; ++i) {
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
[thread start];
[self performSelector:@selector(stopThread) onThread:thread withObject:nil waitUntilDone:YES];
}
}
-(void)stopThread {
CFRunLoopStop(CFRunLoopGetCurrent());
NSThread *thread = [NSThread currentThread];
[thread cancel];
}
-(void)run {
@autoreleasepool {
NSLog(@"current thread = %@", [NSThread currentThread]);
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
if (!port) {
port = [NSPort port];
}
[runLoop addPort:port forMode:NSDefaultRunLoopMode];
[runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
}
複製代碼
關於 Runloop 的介紹我也不在此贅述。就說一下我遇到的問題. 在oop
[runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
複製代碼
這句中,我嘗試着使用了 NSRunLoopCommonModes
,來設定 Mode。就行 ruanloop 運行。 可是我會收到 Crash.測試
可是若是我使用 NSDefaultRunLoopMode
來填充這個 mode 就不會 crash.ui
那麼這是爲啥?spa
個人環境 Xcode:10.2.1 Mac:macOS Mojave version 10.14.4 iPhone: iOS 12.2 iPhone 8 Plus 模擬器線程
1. 使用 Timer 時,也可使用 Common,可是依然可使用。這裏爲啥不行?
2. Runloop 只能在一個特定的模式下運行,那麼 Common 是否是由於包含了多種,因此不能正常使用?(可是 Common 包含了 Default)
複製代碼
帶着思考我去翻了源碼.先看看 Timer 的流程.3d
CFRunLoopAddTimer(_rl, (CFRunLoopTimerRef)timer, (CFStringRef)mode);
rl->_commonModeItems
中,最終添加到新的 Commond 中CFSetApplyFunction(set, (__CFRunLoopAddItemToCommonModes), (void *)context);
複製代碼
因此爲何 time 使用 Common 卻能夠,由於是由於對 Common 對了轉換,作了特殊處理。code
那麼,在來結合源碼看看orm
- (BOOL)runMode:(NSRunLoopMode)mode beforeDate:(NSDate *)limitDate
複製代碼
方法。cdn
他最終會走到 Foundation 中的 moreWork = CFRunLoopRunInMode((CFStringRef)mode, t, true) == kCFRunLoopRunHandledSource;
方法中。
當返回值是 kCFRunLoopRunHandledSource 時,返回一個 true,來完成這次運行。
隨便在說一下這兩個方法,他們爲何不會退出。
接上,那麼底層的 CoreFoundation 會對於傳入不一樣的 mode 作特殊處理嗎? 帶着問題我翻看源碼。
SInt32 CFRunLoopRunInMode(CFStringRef modeName, CFTimeInterval seconds, Boolean returnAfterSourceHandled) { /* DOES CALLOUT */
CHECK_FOR_FORK();
return CFRunLoopRunSpecific(CFRunLoopGetCurrent(), modeName, seconds, returnAfterSourceHandled);
}
複製代碼
其實內部並無作什麼特殊處理,就是一系列判斷。
那麼爲何設置爲 Common 會 crash 了?
我有找了不少資料。
在一片文章中找到了以下內容:
因此會掛的緣由是由於: Common是一個模式合集
,而非一個具體的模式,在這裏須要的是一個具體的模式,因此就會 crash.
另外:
CFRunLoopRun(); // 啓動
CFRunLoopStop(CFRunLoopGetCurrent()); // 中止
複製代碼
這兩個是能夠啓動和中止的.從源碼來看
中止方法,最終會設置中止值。