iOS開發網絡多線程之Runloop無限循環

一. Runloop的基本知識

1. 概念api

    runloop是運動循環,不斷跑圈,無限循環框架

   做用:
oop

    保持程序的持續運行 (iOS程序一直活着的緣由)
性能

    處理App中的各類事件(eg:觸摸事件/定時器事件/selector事件【選擇器·performSelector···】)spa

    節省CPU資源,提升程序的性能(有事作事,沒事休息)
線程

程序已啓動,就開啓了一個runloop無限循環,所以程序才能持續的運行code

  
  
  
  
#import <UIKit/UIKit.h>#import "AppDelegate.h"int main(int argc, char * argv[]) {@autoreleasepool {return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));}}


2. Runloop對象orm

1> 在iOS開發中有兩套api來訪問Runloopserver

  • Foundation框架【NSRunloop】(OC)對象

  • Core Foundation框架【CFRunloopRef】(C)

2> NSRunLoop和CFRunLoopRef都表明着RunLoop對象,它們是等價的,能夠互相轉換

3> NSRunLoop是基於CFRunLoopRef的一層OC包裝,因此要了解RunLoop內部結構,須要多研究CFRunLoopRef層面的API(Core Foundation層面)

  

3. Runloop與線程的關係

1> Runloop和線程的關係:一個Runloop對應着一條惟一的線程

    問題:如何讓子線程不死

    回答:給這條子線程開啓一個Runloop

2> Runloop的建立:主線程Runloop已經建立好了,子線程的runloop須要手動建立

3> Runloop的生命週期:在第一次獲取時建立,在線程結束時銷燬


二. Runloop對象的建立

1. Foundation框架【NSRunloop】建立Runloop對象

  
  
  
  
// 獲取當前線程下的Runloop, 懶加載的形式建立NSRunLoop * runloop1 = [NSRunLoop currentRunLoop];// 獲取主線程下的RunloopNSRunLoop * runloop1 = [NSRunLoop mainRunLoop];

2. Core Foundation框架【CFRunloopRef】建立Runloop對象

  
  
  
  
// 獲取當前線程下的Runloop, 懶加載的形式建立CFRunLoopRef runloop2 = CFRunLoopGetCurrent();// 獲取主線程下的RunloopCFRunLoopRef runloop2 = CFRunLoopGetMain();


3. Runloop運行原理圖

4. Runloop相關的類

  • CFRunloopRef

  • CFRunloopModeRefRunloop的運行模式】

  • CFRunloopSourceRefRunloop要處理的事件源】

  • CFRunloopTimerRefTimer事件】

  • CFRunloopObserverRefRunloop的觀察者(監聽者)】

    Runloop要想跑起來,它的內部必需要有一個mode,mode中必須有source/observer/time,至少要有其中的一個

 

5. CFRunloopModeRefRunloop的運行模式】

    Runloop每次啓動的時候只能指定一個運行模型,切換模式時必須退出當前的Runloop,再從新進入一個mode,是爲了分割不一樣組的定時器互不影響

  • kCFRunLoopDefaultMode:App的默認Mode,一般主線程是在這個Mode下運行

  • UITrackingRunLoopMode:界面跟蹤 Mode,用於 ScrollView 追蹤觸摸滑動,保證界面滑動時不受其餘 Mode 影響

  • UIInitializationRunLoopMode: 在剛啓動 App 時第進入的第一個 Mode,啓動完成後就再也不使用

  • GSEventReceiveRunLoopMode: 接受系統事件的內部 Mode,一般用不到

  • kCFRunLoopCommonModes: 這是一個佔位用的Mode,不是一種真正的Mode

6. CFRunloopTimerRefTimer事件】

1> NSTimer

  
  
  
  
- (void)timer0{NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(show) userInfo:nil repeats:YES];/* NSDefaultRunLoopMode -> kCFRunLoopDefaultMode 默認模式主線程中執行 NSRunLoopCommonModes -> kCFRunLoopDefaultMode/UITrackingRunLoopMode UITrackingRunLoopMode -> 界面追蹤,其餘不工做 */[[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];}

2. GCD定時器

GCD定時器必須必須保存起來才能使用

  
  
  
  
- (void)gcdTimer{NSLog(@"+++++++++");// 1.建立定時器dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(0, 0));// 2.設置定時器/* 第一個參數:定時器 第二個參數:從哪一個時間開始 第三個參數:間隔時間 第四個參數:精確度, 0表明無偏差 */ dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 2.0 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);// 3.定時器觸發事件 dispatch_source_set_event_handler(timer, ^{NSLog(@"----------");});// 4.開啓定時器 dispatch_resume(timer);// GCD定時器建立是個局部變量須要保存才能執行 self.timer = timer;}

7. CFRunloopSourceRefRunloop要處理的事件源】

1)之前的分法

Port-Based Sources

Custom Input Sources

Cocoa Perform Selector Sources


2)如今的分法

Source0:非基於Port的 (用戶觸發的時間)

Source1:基於Port的 (經過內核和其它線程相互發送消息)


8. CFRunloopObserverRefRunloop的觀察者(監聽者)】

  
  
  
  
- (void)observer{// 建立一個觀察者/* 第一個參數:獲取內存的方式 第二個參數:監聽哪些狀態 第三個參數:是否持續監聽 第四個參數:0 第五個參數:block代碼塊 kCFRunLoopEntry = (1UL << 0), 準備進入 kCFRunLoopBeforeTimers = (1UL << 1), 即將處理timer事件 kCFRunLoopBeforeSources = (1UL << 2), 即將處理source事件 kCFRunLoopBeforeWaiting = (1UL << 5), 即將進入休眠 kCFRunLoopAfterWaiting = (1UL << 6), 喚醒 kCFRunLoopExit = (1UL << 7), 退出 kCFRunLoopAllActivities = 0x0FFFFFFFU 全部 */CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {switch (activity) {case kCFRunLoopEntry:NSLog(@"準備進入");break;case kCFRunLoopBeforeTimers:NSLog(@"即將處理timer事件");break;case kCFRunLoopBeforeSources:NSLog(@"即將處理source事件");break;case kCFRunLoopBeforeWaiting:NSLog(@"即將進入休眠");break;case kCFRunLoopAfterWaiting:NSLog(@"喚醒");break;case kCFRunLoopExit:NSLog(@"退出");break;}});// 給runloop添加一個觀察者CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(show) userInfo:nil repeats:YES];// 釋放觀察者CFRelease(observer);}


9. Runloop運行邏輯


相關文章
相關標籤/搜索