国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

iOS開發日記24-RunLoop終極篇

2019-11-14 18:16:21
字體:
來源:轉載
供稿:網友

今天博主有一個RunLoop的需求,遇到了一些困難點,在此和大家分享,希望能夠共同進步.

RunLoop是什么?

從字面上理解,Runloop指的就是運行循環,iOS中,只要程序啟動, 就會創建Runloop,用來處理各種事件(比如定時器事件, 觸摸事件等).

它的主要作用有以下幾個:

1.保持程序的運行:如果沒有它, 程序一啟動就over了;

2.事件的處理: 包括按鈕點擊事件, 屏幕的點擊事件等;

3.定時器處理: NSTimer的處理;

4.節約CPU, 提高性能:有任務的時候干活,沒有任務時候休息.

在iOS中, 可以通過兩套API來訪問Runloop:

1.Foundation框架: OC中的框架, 直接訪問NSRunLoop對象.

2.Core Foundation框架: c語言的框架, 通過CFRunLooPRef訪問.

實際上, NSRunLoop和CFRunLoopRef是同一個對象, 只不過通過不同的API來訪問的,NSRunLoop是對CFRunLoopRef的封裝.

 

OC中, 使用下面代碼就可以獲得Runloop對象:

// Foundation

[NSRunLoop currentRunLoop]; // 獲得當前線程的RunLoop對象

[NSRunLoop mainRunLoop]; // 獲得主線程的RunLoop對象

// Core Foundation

CFRunLoopGetCurrent(); // 獲得當前線程的RunLoop對象

CFRunLoopGetMain(); // 獲得主線程的RunLoop對象

 

Nslog打印Runloop對象, 里面的內容如下:(由于內容比較多, 只將重點內容列出)

 // runloop對象 <CFRunLoop 0x7fb13172abc0 [0x10a5aa180]>{wakeup port = 0x1003, stopped = false, ignoreWakeUps = true,// 當前模式current mode = UIInitializationRunLoopMode,common modes = <CFBasicHash 0x7fb13172ac80// common modes標記了哪兩個模式(后面會講為啥是標記?)    0 : <CFString 0x10b27ce50 [0x10a5aa180]>{contents = "UITrackingRunLoopMode"}    2 : <CFString 0x10a586080 [0x10a5aa180]>{contents = "kCFRunLoopDefaultMode"}}// source: 源6 : <CFRunLoopSource 0x7fb131415300 [0x10a5aa180]>// observers: 觀察者observers = <CFArray 0x7fb13141d300 [0x10a5aa180]>// timer: 定時器timers = (null),// 兩種不同的模式3 : <CFRunLoopMode 0x7fb13172dbb0 [0x10a5aa180]>{name = GSEventReceiveRunLoopMode, port set = 0x2003, timer port = 0x2103,    sources0 = <CFBasicHash 0x7fb13172d260 [0x10a5aa180]>{type = mutable set, count = 1,entries =>    0 : <CFRunLoopSource 0x7fb13172da30 [0x10a5aa180]>{signalled = No, valid = Yes, order = -1, context = <CFRunLoopSource context>{version = 0, info = 0x0, callout = PurpleEventSignalCallback (0x10d8236c8)}}}

要想知道上面內容是什么意思, 先看下面的內容:

Core Foundation中關于RunLoop的5個類1.CFRunLoopRef2.CFRunLoopModeRef3.CFRunLoopSourceRef4.CFRunLoopTimerRef5.CFRunLoopObserverRef
可以這理解為, 一個Runloop對象里面, 必不可少的是CFRunLoopModeRef, Mode里面可以包含timer/source/oberver(只有包含了其中一個, Runloop才能在啟動后保證不死)

層級結構如下圖:

接下來, 對里面的內容說明一下:

一.CFRunLoopModeRef:代表RunLoop的運行模式    1.一個RunLoop包含若干個Mode,每個Mode又包含若干個Source/Timer/Observer    2.每次RunLoop啟動時,只能指定其中一個 Mode,這個Mode被稱作CurrentMode    3.這樣做主要是為了分隔開不同組的Source/Timer/Observer,讓其互不影響系統默認注冊了5個Mode:    1.kCFRunLoopDefaultMode:App的默認Mode,通常主線程是在這個Mode下運行    2.UITrackingRunLoopMode:界面跟蹤 Mode,用于 ScrollView 追蹤觸摸滑動,保證界面滑動時不受其他 Mode 影響    3.UIInitializationRunLoopMode: 在剛啟動 App 時第進入的第一個 Mode,啟動完成后就不再使用    4.GSEventReceiveRunLoopMode: 接受系統事件的內部 Mode,通常用不到    5.kCFRunLoopCommonModes: 這是一個占位用的Mode,不是一種真正的Mode, 被標記為kCFRunLoopCommonModes格式的都可以成為commonMode, 其中包含1.2兩種模式.二.CFRunLoopSourceRef:是事件源(輸入源)    現在主要分為兩種:    Source0:非基于Port的    Source1:基于Port的(如GCD底層實現也是通過Port的, 主要用于線程之間的通信)三.CFRunLoopTimerRef:是基于時間的觸發器, 基本上說的就是NSTimer四.CFRunLoopObserverRef:觀察者, 可以用來監聽Runloop的狀態, 下面列出了Runloop的狀態typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {    kCFRunLoopEntry = (1UL << 0), // 即將進入    kCFRunLoopBeforeTimers = (1UL << 1), // 即將處理timer    kCFRunLoopBeforeSources = (1UL << 2), // 即將處理事件源    kCFRunLoopBeforeWaiting = (1UL << 5), // 即將進入休眠    kCFRunLoopAfterWaiting = (1UL << 6), // 剛從休眠中喚醒    kCFRunLoopExit = (1UL << 7), // 即將退出Runloop};

下面圖片描述了Runloop的運行和狀態:

Runloop的寄生于線程:一個線程只能有唯一對應的runloop;但這個根runloop里可以嵌套子runloops;
自動釋放池寄生于Runloop:程序啟動后,主線程注冊了兩個Observer監聽runloop的進出與睡覺。一個最高優先級OB監測Entry狀態;一個最低優先級OB監聽BeforeWaiting狀態和Exit狀態。
線程(創建)-->runloop將進入-->最高優先級OB創建釋放池-->runloop將睡-->最低優先級OB銷毀舊池創建新池-->runloop將退出-->最低優先級OB銷毀新池-->線程(銷毀)

Mach是XNU的內核,進程、線程和虛擬內存等對象通過端口發消息進行通信,Runloop通過mach_msg()函數發送消息,如果沒有port 消息,內核會將線程置于等待狀態 mach_msg_trap() 。如果有消息,判斷消息類型處理事件,并通過modeItem的callback回調。

Runloop有兩個關鍵判斷點,一個是通過msg決定Runloop是否等待,一個是通過判斷退出條件來決定Runloop是否循環。

 

應用1:滑動與圖片刷新:

當tableview的cell上有需要從網絡獲取的圖片的時候,滾動tableView,異步線程會去加載圖片,加載完成后主線程就會設置cell的圖片,但是會造成卡頓??梢宰屧O置圖片的任務在CFRunLoopDefaultMode下進行,當滾動tableView的時候,RunLoop是在 UITrackingRunLoopMode 下進行,不去設置圖片,而是當停止的時候,再去設置圖片。

- (void)viewDidLoad { 

[super viewDidLoad];  // 只在NSDefaultRunLoopMode下執行(刷新圖片) 

[self.myImageView performSelector:@selector(setImage:) withObject:[UIImage imageNamed:@""] afterDelay:ti inModes:@[NSDefaultRunLoopMode]];  

 }

應用2:常駐子線程,保持子線程一直處理事件
為了保證線程長期運轉,可以在子線程中加入RunLoop,并且給Runloop設置item,防止Runloop自動退出。

+ (void)networkRequestThreadEntryPoint:(id)__unused object {    @autoreleasepool {        [[NSThread currentThread] setName:@"AFNetworking"];        NSRunLoop *runLoop = [NSRunLoop currentRunLoop];        [runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];        [runLoop run];    }}+ (NSThread *)networkRequestThread {    static NSThread *_networkRequestThread = nil;    static dispatch_once_t oncePredicate;    dispatch_once(&oncePredicate, ^{        _networkRequestThread = [[NSThread alloc] initWithTarget:self selector:@selector(networkRequestThreadEntryPoint:) object:nil];        [_networkRequestThread start];    });    return _networkRequestThread;}- (void)start {    [self.lock lock];    if ([self isCancelled]) {        [self performSelector:@selector(cancelConnection) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]];    } else if ([self isReady]) {        self.state = AFOperationExecutingState;        [self performSelector:@selector(operationDidStart) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]];    }    [self.lock unlock];}


http://www.survivalescaperooms.com/66it/p/4719701.html?utm_source=tuicool
http://blog.ibireme.com/2015/05/18/runloop/

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 嘉荫县| 武威市| 滨海县| 七台河市| 鹰潭市| 凤城市| 青阳县| 手游| 东丽区| 乡宁县| 柞水县| 赤峰市| 德阳市| 湘潭市| 宣汉县| 河间市| 霍州市| 金阳县| 周至县| 璧山县| 长垣县| 曲阜市| 高唐县| 来安县| 塔河县| 郸城县| 张家口市| 筠连县| 泸西县| 泰来县| 鹤岗市| 九龙县| 北辰区| 闽清县| 鄂伦春自治旗| 聂拉木县| 吐鲁番市| 色达县| 加查县| 广宁县| 四平市|