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