特點(diǎn):
1.runloop和線程有關(guān)面徽,一個(gè)線程里只有一個(gè)runloop艳丛,所以不同的runloop會(huì)出現(xiàn)在不同的線程里。
2.同一個(gè)runloop不同模式下會(huì)出現(xiàn)阻塞趟紊,所以相同模式下一定不會(huì)出現(xiàn)阻塞氮双。
3.主線程的runloop默認(rèn)開(kāi)啟,子線程的runloop默認(rèn)不開(kāi)啟霎匈,子線程在執(zhí)行完畢后會(huì)自動(dòng)銷(xiāo)毀戴差,所以子線程只會(huì)讓runloop轉(zhuǎn)一次。
作用:
1.保證線程不退出
2.負(fù)責(zé)監(jiān)聽(tīng)所有事件:觸摸事件铛嘱,時(shí)鐘暖释,網(wǎng)絡(luò)事件......
3.負(fù)責(zé)渲染UI,runloop一次循環(huán)渲染整個(gè)界面(哪怕滑動(dòng)屏幕一點(diǎn)點(diǎn))
4.如果沒(méi)有事件發(fā)生墨吓,runloop就去睡覺(jué)了
模式mode
1.NSDefaultRunloopMode:默認(rèn)模式球匕,一般用于處理timer
2.UITrackingRunloopMode:用戶(hù)交互模式,默認(rèn)處理UI事件
3.NSRunloopCommonModes:占位模式帖烘,既是默認(rèn)模式亮曹,又是交互模式,Default和Tracking都能觸發(fā)
4.UIInitializationRunLoopMode: 啟動(dòng)程序后的過(guò)渡mode秘症,啟動(dòng)完成后就不再使用照卦。
5.GSEventReceiveRunLoopMode: Graphic相關(guān)事件的mode,通常用不到历极。
runloop沒(méi)事兒就睡覺(jué)窄瘟,能讓runloop保持清醒的也就source,observer趟卸,timer了蹄葱。
定時(shí)器
(1)NSTimer
-(void)nsTimer
{
//將timer放到子線程里的做法
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(run) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
//保持線程活動(dòng)狀態(tài)
[[NSRunLoop currentRunLoop] run];
});
}
-(void)run
{
static int num = 0;
[NSThread sleepForTimeInterval:1.0];
NSLog(@"%d---%@",num++,[NSThread currentThread]);
}
(2)GCD方式比NSTimer準(zhǔn)確,因?yàn)閱挝皇羌{秒
@property(nonatomic,strong)dispatch_source_t timer;
-(void)dispatchSource
{
//GCD方式之所以準(zhǔn)確是因?yàn)閱挝皇羌{秒
//dispatch_source_t timer這是個(gè)OC對(duì)象
self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(0, 0));
//timer設(shè)置
dispatch_source_set_timer(self.timer, DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC, 0);
dispatch_source_set_event_handler(self.timer, ^{
NSLog(@"----------%@",[NSThread currentThread]);
});
//啟動(dòng)定時(shí)器
dispatch_resume(self.timer);
}
Observer
//以下是C代碼
-(void)addRunloopObserver
{
//拿到當(dāng)前runloop
//凡是在CoreFoundation里面看到Ref锄列,就代表指針图云!
CFRunLoopRef runloop = CFRunLoopGetCurrent();
/**
參數(shù)說(shuō)明:
CFOptionFlags activities:枚舉類(lèi)型
CFRunLoopObserverCallBack callout:函數(shù)指針
CFRunLoopObserverContext *context:給callback函數(shù)傳遞的參數(shù)
*/
static CFRunLoopObserverRef observer;
//定義一個(gè)結(jié)構(gòu)體類(lèi)型context
CFRunLoopObserverContext context = {
/**
CFIndex version;
void * info;信息
const void *(*retain)(const void *info);處理哪個(gè)函數(shù)
void (*release)(const void *info);
CFStringRef (*copyDescription)(const void *info);
*/
0,
(__bridge void *)self,
&CFRetain,
&CFRelease,
NULL
};
//創(chuàng)建一個(gè)觀察者
observer = CFRunLoopObserverCreate(NULL, kCFRunLoopBeforeWaiting, YES, 0, &CallBack, &context);
//添加觀察者
CFRunLoopAddObserver(runloop, observer, kCFRunLoopDefaultMode);
//必須釋放觀察者
CFRelease(observer);
}
void CallBack(){
printf("CallBack");
}
運(yùn)行代碼發(fā)現(xiàn),滾動(dòng)屏幕過(guò)程中邻邮,CallBack()函數(shù)會(huì)暫停調(diào)用竣况,松手會(huì)繼續(xù)調(diào)用,因?yàn)樘砑佑^察者時(shí)使用的kCFRunLoopDefaultMode筒严,如果使用kCFRunLoopCommonModes會(huì)同時(shí)持有default和tracking兩種模式丹泉,就不會(huì)有阻塞現(xiàn)象情萤。
用途:CFRunloop+Observer可以解決圖片加載卡頓問(wèn)題。原理就是讓runloop每轉(zhuǎn)一次摹恨,加載一張筋岛。設(shè)置一個(gè)數(shù)組,用于存放當(dāng)前屏幕顯示的圖的數(shù)量晒哄,在觀察者監(jiān)聽(tīng)的方法中睁宰,每次移除第0個(gè)元素,添加一個(gè)新元素寝凌,效果更流暢柒傻。流暢加載高清大圖demo