1.RunLoop使用
RunLoop又稱(chēng)運(yùn)行循環(huán),保證app程序一直運(yùn)行的的基礎(chǔ)掐暮。
一般程序在運(yùn)行完代碼后就結(jié)束運(yùn)行涂佃,要時(shí)程序一直運(yùn)行,則需要一個(gè)while循環(huán)灵莲,保證程序不退出雕凹。RunLoop就是這樣的角色存在,在有任務(wù)時(shí)處理任務(wù),沒(méi)有任務(wù)時(shí)進(jìn)入休眠狀態(tài)枚抵。
在iOS開(kāi)發(fā)中线欲,RunLoop與線(xiàn)程為一一對(duì)應(yīng)的關(guān)系,每個(gè)線(xiàn)程有自己的RunLoop汽摹,線(xiàn)程與RunLoop的關(guān)系保存在一個(gè)全局字典中李丰,key為線(xiàn)程,value為RunLoop逼泣。主線(xiàn)程RunLoop為系統(tǒng)啟動(dòng)趴泌,無(wú)需程序員管理,子線(xiàn)程的RunLoop為懶加載圾旨,需要程序員主動(dòng)調(diào)用才會(huì)創(chuàng)建踱讨,否則子線(xiàn)程執(zhí)行完任務(wù)就退出。
蘋(píng)果官方的RunLoop示意圖如下:
官方文檔
簡(jiǎn)單創(chuàng)建一個(gè)線(xiàn)程并激活RunLoop代碼如下:
@interface ViewController ()
@property(nonatomic,weak)NSThread* thread;
@end
@implementation ViewController
- (void)ThreadRun:(id)object {
NSLog(@"%@",[NSThread currentThread]);
NSLog(@"%s %@",__FUNCTION__,object);
}
- (void)viewDidLoad {
[super viewDidLoad];
NSThread *thread = [[NSThread alloc] initWithBlock:^{
//添加port才能激活
[[NSRunLoop currentRunLoop] addPort:[[NSPort alloc] init] forMode:NSDefaultRunLoopMode];
//添加定時(shí)器也可以激活
//NSTimer *timer = [NSTimer timerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {
//NSLog(@"block run");
//}];
//[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] run];
}];
[thread start];
self.thread = thread;
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
//可以在該線(xiàn)程不斷添加新任務(wù)
[self performSelector:@selector(ThreadRun:) onThread:self.thread withObject:self waitUntilDone:NO];
}
@end
RunLoop每次運(yùn)行需要處理的事件分為3類(lèi):Observer監(jiān)聽(tīng)事件砍的,Timer定時(shí)器事件與Source輸入源事件痹筛。其中,Source輸入源事件又可以分為Source0和Source1:Source0事件不會(huì)主動(dòng)觸發(fā)廓鞠,需要將其標(biāo)記為待處理之后手動(dòng)喚醒RunLoop進(jìn)行處理帚稠;Source1事件會(huì)主動(dòng)喚醒RunLoop進(jìn)行處理,通常用來(lái)線(xiàn)程間通信和處理硬件接口的信號(hào)床佳。Timer事件特指定時(shí)器的回調(diào)滋早,當(dāng)定時(shí)器被添加進(jìn)RunLoop時(shí),會(huì)根據(jù)設(shè)置的定時(shí)器頻率在RunLoop中注冊(cè)一系列的時(shí)間點(diǎn)砌们,當(dāng)時(shí)間點(diǎn)到時(shí)會(huì)喚醒RunLoop進(jìn)行事件處理杆麸。Observer事件用來(lái)監(jiān)聽(tīng)RunLoop狀態(tài)的變化,當(dāng)RunLoop狀態(tài)變化時(shí)會(huì)觸發(fā)對(duì)應(yīng)的回調(diào)浪感。
有需要的時(shí)候我們可以添加監(jiān)聽(tīng)昔头,方法如下,可以在排查app卡頓的時(shí)候使用影兽。
CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
NSLog(@"%lu",activity);
});
CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);
2.RunLoop的模式
RunLoop可以通過(guò)模式來(lái)篩選其要處理的事件,NSRunLoopMode為字符串類(lèi)型揭斧,用戶(hù)除了可以使用系統(tǒng)設(shè)置的Mode,也可以自定義Mode
typedef NSString * NSRunLoopMode NS_TYPED_EXTENSIBLE_ENUM;
供用戶(hù)使用的mode如下峻堰,當(dāng)我們需要在滑動(dòng)頁(yè)面添加定時(shí)器時(shí)讹开,可以把定時(shí)器添加到NSRunLoopCommonModes。
FOUNDATION_EXPORT NSRunLoopMode const NSDefaultRunLoopMode;
FOUNDATION_EXPORT NSRunLoopMode const NSRunLoopCommonModes API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
系統(tǒng)使用的mode如下捐名,這些mode我們無(wú)需使用旦万。
NSRunLoopCommonModes //A pseudo-mode that includes one or more other run loop modes.
NSDefaultRunLoopMode //The mode set to handle input sources other than connection objects.
NSEventTrackingRunLoopMode //The mode set when tracking events modally, such as a mouse-dragging loop.
NSModalPanelRunLoopMode //The mode set when waiting for input from a modal panel, such as a save or open panel.
UITrackingRunLoopMode //The mode set while tracking in controls takes place.