RunLoop是控制線程生命周期并接收事件進(jìn)行處理的機(jī)制.是iOS事件響應(yīng)與任務(wù)處理最核心的機(jī)制.
主線程的RunLoop在應(yīng)用啟動(dòng)時(shí)自動(dòng)創(chuàng)建,讓主程序死循環(huán),保證程序不退出,防止用戶不對(duì)app做出操作導(dǎo)致退出app.
但這個(gè)死循環(huán)是一個(gè)很特殊的死循環(huán), 它能夠在有事情的時(shí)候做事情, 沒(méi)事情做的時(shí)候休息待命, 以節(jié)省CPU資源, 提高程序性能.
實(shí)現(xiàn)省電,流暢,響應(yīng)速度快,用戶體驗(yàn)好
實(shí)際應(yīng)用有:
1.定時(shí)器
注冊(cè)到RunLoop之后,RunLoop會(huì)為其在重復(fù)的時(shí)間點(diǎn)注冊(cè)好事件執(zhí)行.
1.1 NSTimer
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.5 target:self selector:@selector(FunctionName) userInfo:nil repeats:YES];
self.timer = timer;
[[NSRunLoop mainRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
1.2 CADisplayLink
CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(FunctionName)];
self.link = link;
[link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
注意:定時(shí)器不使用一定要銷毀!
其中NSRunLoopCommonModes包含kCFRunLoopDefaultMode(NSDefaultRunLoopMode)UITrackingRunLoopMode兩種模式
保證時(shí)鐘在兩種RunLoop運(yùn)行模式下都能被監(jiān)聽(tīng)到.
1.3 GCD
GCD定時(shí)器會(huì)自動(dòng)開(kāi)啟一條子線程,子線程中也會(huì)自己開(kāi)啟了runloop.自己創(chuàng)建,自己管理,全不用我們手動(dòng)管理
//首先聲明屬性
@property (strong, nonatomic) dispatch_source_t timer;
//然后是方法:
- (void)GCDTimer {
/*
參數(shù)1 : 需要?jiǎng)?chuàng)建的源的種類, timer 也是一種數(shù)據(jù)源
參數(shù)2,參數(shù)3: 在你創(chuàng)建timer的時(shí)候直接傳0就可以了
參數(shù)4: timer觸發(fā)的代碼運(yùn)行的隊(duì)列
*/
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
/*
參數(shù)1 : timer定時(shí)器
參數(shù)2 : 從什么時(shí)間開(kāi)始觸發(fā)定時(shí)器, DISPATCH_TIME_NOW代表現(xiàn)在
參數(shù)3 : 時(shí)間間隔
參數(shù)4 : 表示精度, 傳0表示絕對(duì)精準(zhǔn)
*/
dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 2.0 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
//封裝timer需要觸發(fā)的方法
dispatch_source_set_event_handler(timer, ^{
//當(dāng)前線程是子線程
NSLog(@"GCDTimer-----%@",[NSThread currentThread]);
NSLog(@"每?jī)擅氪蛴∫淮?);
});
//啟用,默認(rèn)是停止的
dispatch_resume(timer);
//用強(qiáng)指針引用, 防止timer釋放
self.timer = timer;
}
2.自動(dòng)釋放池
自動(dòng)釋放池在什么時(shí)候創(chuàng)建?什么時(shí)候銷毀晨抡?
創(chuàng)建: 運(yùn)行循環(huán)檢測(cè)到事件并啟動(dòng)之后淹办,就會(huì)創(chuàng)建自動(dòng)釋放池
銷毀: 一次完整的運(yùn)行循環(huán)結(jié)束之前,會(huì)被銷毀
經(jīng)典錯(cuò)誤:
for (long i = 0; i < largeNumber; ++i)
{
NSString *str = [NSString stringWithFormat:@"hello ) %ld", i];
str = [str uppercaseString];
str = [str stringByAppendingString:@" ) world"];
}
分析:
代碼有問(wèn)題税娜,但是并不是說(shuō) largeNumber 沒(méi)有定義悉抵,這個(gè)不是重點(diǎn)
重點(diǎn)是 largeNumber 值我們不知道,如果 largeNumber 值非常大验残,內(nèi)存就會(huì)很高
解決:
引入自動(dòng)釋放池,提前釋放對(duì)象
for (long i = 0; i < largeNumber; ++i)
{
@autoreleasepool {
NSString *str = [NSString stringWithFormat:@"hello ) %ld", i];
str = [str uppercaseString];
str = [str stringByAppendingString:@" ) world"];
}
}
其中,在循環(huán)內(nèi)添加自動(dòng)釋放池會(huì)更佳
循環(huán)內(nèi)的運(yùn)行速度比循環(huán)外的要快
循環(huán)外的會(huì)有內(nèi)存峰值,如果峰值太大己肮,會(huì)造成程序閃退
如果在開(kāi)發(fā)中,遇到部份內(nèi)存峰值很高悲关,可以嘗試添加自動(dòng)釋放池
3.操縱線程
3.1可以用RunLoop實(shí)現(xiàn)將一個(gè)函數(shù)調(diào)用在主線程執(zhí)行
[[NSRunLoop mainRunLoop] performSelector:@selector(FunctionName) withObject:nil];
此外還有三種方式可以實(shí)現(xiàn):
1>GCD:
dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 執(zhí)?耗時(shí)的異步操作...
dispatch_async(dispatch_get_main_queue(), ^{
// 回到主線程,執(zhí)?UI刷新操作
});
});
2>NSOperation:
NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
NSBlockOperation *operation = [NSBlockOperation blockOpertionWithBlock:^{
}];
[mainQueue addOperation:operation];
3>NSThread:
[self performSelector:@selector(FunctionName) onThread:[NSThread mainThread] withObject:nil waitUntilDone:YES modes:nil];
[self performSelectorOnMainThread:@selector(method) withObject:nil];
4>pThread 沒(méi)用過(guò)
pthread_t:線程ID
pthread_attr_t:線程屬性
pthread_create():創(chuàng)建一個(gè)線程
pthread_exit():終止當(dāng)前線程
pthread_cancel():中斷另外一個(gè)線程的運(yùn)行
pthread_join():阻塞當(dāng)前的線程谎僻,直到另外一個(gè)線程運(yùn)行結(jié)束
pthread_attr_init():初始化線程的屬性
pthread_attr_setdetachstate():設(shè)置脫離狀態(tài)的屬性(決定這個(gè)線程在終止時(shí)是否可以被結(jié)合)
pthread_attr_getdetachstate():獲取脫離狀態(tài)的屬性
pthread_attr_destroy():刪除線程的屬性
pthread_kill():向線程發(fā)送一個(gè)信號(hào)
pthread_equal(): 對(duì)兩個(gè)線程的線程標(biāo)識(shí)號(hào)進(jìn)行比較
pthread_detach(): 分離線程
pthread_self(): 查詢線程自身線程標(biāo)識(shí)號(hào)
3.2常駐線程
讓一個(gè)子線程不被銷毀, 等待其他線程發(fā)來(lái)消息, 處理事件
沒(méi)用過(guò)