RunLoop應(yīng)用場(chǎng)景
- 開(kāi)啟一個(gè)常駐線程(讓一個(gè)子線程不進(jìn)入消亡狀態(tài),等待其他線程發(fā)來(lái)消息庶近,處理其他事件)
- 在子線程中開(kāi)啟一個(gè)定時(shí)器(或添加port)
- 在子線程中進(jìn)行一些長(zhǎng)期監(jiān)控
- 可以控制定時(shí)器在哪種模式下運(yùn)行
- 可以讓某些事件(行為、任務(wù))在特定模式下執(zhí)行
- 可以添加Observer監(jiān)聽(tīng)RunLoop的狀態(tài)眷蚓,比如監(jiān)聽(tīng)點(diǎn)擊事件的處理(在所有點(diǎn)擊事件之前做一些事情)
常駐線程
讓一個(gè)子線程不進(jìn)入消亡狀態(tài)鼻种,等待其他線程發(fā)來(lái)消息,處理其他事件
- 聲明一個(gè)NSThread屬性:
@property (nonatomic, strong) NSThread *thread;
- 開(kāi)啟線程
- (void)viewDidLoad {
[super viewDidLoad];
self.thread = [[NSThread alloc]initWithTarget:self selector:@selector(run) object:nil];
[self.thread start];
}
- (void)run {
// RunLoop如果當(dāng)前mode中沒(méi)有任何Sources(Source0沙热、Source1)叉钥、Timer,那么就會(huì)直接退出RunLoop
@autoreleasepool {
// 在此線程開(kāi)啟RunLoop ---> 讓線程不死
[[NSRunLoop currentRunLoop] addPort:[NSPort port] forMode:NSDefaultRunLoopMode]; // 添加port相當(dāng)于添加Source
[[NSRunLoop currentRunLoop] run];
}
}
注意:常駐線程啟動(dòng)RunLoop最好放到autoreleasepool里面
作用:清掉創(chuàng)建的臨時(shí)變量(主線程的RunLoop會(huì)自動(dòng)在RunLoop睡眠前釋放舊的釋放池然后自動(dòng)創(chuàng)建新的釋放池篙贸,子線程的RunLoop最好添加個(gè)大釋放池包裹淄抖印)
- 往常駐線程中發(fā)送消息
[self performSelector:@selector(work) onThread:self.thread withObject:nil waitUntilDone:NO];
常駐線程的好處
- 讓一個(gè)子線程不進(jìn)入消亡狀態(tài),等待其他線程發(fā)來(lái)消息歉秫,處理其他事件(AFNetworking框架里面就使用了常駐線程)
定時(shí)器與RunLoop
控制定時(shí)器在哪種模式下運(yùn)行
NSTimer:
- scheduledTimerWithTimeInterval ---- 自動(dòng)添加到當(dāng)前RunLoop中蛾洛,而且是NSDefaultRunLoopMode,可手動(dòng)修改模式
- timerWithTimeInterval ---- 需要手動(dòng)添加到runLoop
NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(timer) userInfo:nil repeats:YES];
// 將定時(shí)器放入RunLoop中
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
模式:
- NSDefaultRunLoopMode:一旦RunLoop進(jìn)入其他模式(例如滾動(dòng)的mode),這個(gè)定時(shí)器就不會(huì)工作
- NSRunLoopCommonModes:將定時(shí)器加入到標(biāo)記為common modes的模式下轧膘,只要RunLoop知道有這個(gè)模式的存在钞螟,不管RunLoop在哪個(gè)模式都會(huì)執(zhí)行這個(gè)標(biāo)記的模式(即使在滾動(dòng)的UITrackingRunLoopMode下也會(huì)執(zhí)行)
Observer與RunLoop
添加Observer監(jiān)聽(tīng)RunLoop的狀態(tài),比如監(jiān)聽(tīng)點(diǎn)擊事件的處理(在所有點(diǎn)擊事件之前做一些事情)
// 創(chuàng)建觀察者
CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
// 狀態(tài)改變時(shí)回調(diào)的block
NSLog(@"RunLoop狀態(tài) %lu",activity);
});
// 添加觀察者:監(jiān)聽(tīng)RunLoop的狀態(tài)
// 參數(shù)1:線程的RunLoop對(duì)象
// 參數(shù)2:觀察者
// 參數(shù)3:需要監(jiān)聽(tīng)RunLoop對(duì)象所在的模式
CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);
// ARC模式下C語(yǔ)言層面的對(duì)象需要手動(dòng)釋放內(nèi)存
// 釋放Observer
CFRelease(observer);
注意:創(chuàng)建了Observer記得要release
RunLoop的狀態(tài)
- kCFRunLoopEntry = (1UL << 0), //即將進(jìn)入loop 1
- kCFRunLoopBeforeTimers = (1UL << 1), //即將處理Timer 2
- kCFRunLoopBeforeSources = (1UL << 2), //即將處理Sources 4
- kCFRunLoopBeforeWaiting = (1UL << 5), //即將進(jìn)入休眠 32
- kCFRunLoopAfterWaiting = (1UL << 6), //剛從休眠中喚醒 64
- kCFRunLoopExit = (1UL << 7), //即將退出loop 128
- kCFRunLoopAllActivities = 0x0FFFFFFFU //所有狀態(tài)
UL是無(wú)符號(hào)長(zhǎng)整數(shù)的意思
1UL<<0:0b00000001
1UL<<1:0b00000010
1UL<<2:0b00000100
1UL<<3:0b00001000
0x0FFFFFFF是整形int變量里能保存的最大數(shù)
讓某些事件(行為谎碍、任務(wù))在特定模式下執(zhí)行
設(shè)置圖片不在滾動(dòng)視圖滾動(dòng)期間顯示
[self.imageView performSelector:@selector(setImage:) withObject:[UIImage imageNamed:@"01"] afterDelay:3.0 inModes:@[NSDefaultRunLoopMode]];