1. 程式人生 > >iOS開發 底層拋析執行迴圈—— RunLoop

iOS開發 底層拋析執行迴圈—— RunLoop

這裡寫圖片描述

一.RunLoop基本概念

概念:程式的執行迴圈,通俗的來說就是跑圈.

1. 基本作用(作用重大)
(1) 保持程式的持續執行(ios程式為什麼能一直活著不會死)
(2) 處理app中的各種事件(比如觸控事件、定時器事件【NSTimer】、selector事件【選擇器·performSelector···】)
(3)節省CPU資源,提高程式效能,有事情就做事情,沒事情就休息

2. 重要說明
(1)如果沒有Runloop,那麼程式一啟動就會退出,什麼事情都做不了。
(2)如果有了Runloop,那麼相當於在內部有一個死迴圈,能夠保證程式的持續執行

3.main函式中的Runloop


(1) 在UIApplication函式內部就啟動了一個Runloop,該函式返回一個int型別的值
(2) 這個預設啟動的Runloop是跟主執行緒相關聯的

4.Runloop物件
(1)在iOS開發中有兩套api來訪問Runloop
第一種:foundation框架【NSRunloop】
第二種:core foundation框架【CFRunloopRef】
(2)NSRunLoop和CFRunLoopRef都代表著RunLoop物件,它們是等價的,可以互相轉換
(3)NSRunLoop是基於CFRunLoopRef的一層OC包裝,所以要了解RunLoop內部結構,需要多研究CFRunLoopRef層面的API(Core Foundation層面)

5.Runloop與執行緒
(1) Runloop和執行緒的關係:一個Runloop對應著一條唯一的執行緒
問題:如何讓子執行緒不死
回答:給這條子執行緒開啟一個Runloop
(2) Runloop的建立:主執行緒Runloop已經建立好了,子執行緒的runloop需要手動建立
(3) Runloop的生命週期:在第一次獲取時建立,線上程結束時銷燬
(4) 拿到當前應用程式的主Runloop(主執行緒對應的Runloop)

方法一: NSRunloop

    NSRunLoop * runloop1 = [NSRunLoop mainRunLoop];

方法二: CFRunLoopRef

 CFRunLoopRef runloop2 =   CFRunLoopGetMain();

(5) 注意點:開一個子執行緒建立runloop,不是通過alloc init方法建立,而是直接通過呼叫currentRunLoop方法來建立,它本身是一個懶載入的。

二.Runloop執行原理

1.蘋果官方的執行原理圖
這裡寫圖片描述

2.Runloop和相關類之間的關係圖
這裡寫圖片描述

RunLoop五個相關的類

  • CFRunloopRef
  • CFRunloopModeRef【Runloop的執行模式】
  • CFRunloopSourceRef【Runloop要處理的事件源】
  • CFRunloopTimerRef【Timer事件】
  • CFRunloopObserverRef【Runloop的觀察者(監聽者)】

    以下是五個相關類的拋析:

  • CFRunloopRef
    (1) CFRunloopModeRef代表著Runloop的執行模式
    (2) 一個Runloop中可以有多個mode,一個mode裡面又可以有多個source\observer\timer等等
    (3) 每次runloop啟動的時候,只能指定一個mode,這個mode被稱為該Runloop的當前mode
    (4) 如果需要切換mode,只能先退出當前Runloop,再重新指定一個mode進入
    (5) 這樣做主要是為了分割不同組的定時器等,讓他們相互之間不受影響
    (6) 系統預設註冊了5個mode
    第一種模式: kCFRunLoopDefaultMode:App的預設Mode,通常主執行緒是在這個Mode下執行
    第二種模式: UITrackingRunLoopMode:介面跟蹤 Mode,用於 ScrollView 追蹤觸控滑動,保證介面滑動時不受其他 Mode 影響
    第三種模式: UIInitializationRunLoopMode: 在剛啟動 App 時第進入的第一個 Mode,啟動完成後就不再使用
    第四種模式: GSEventReceiveRunLoopMode: 接受系統事件的內部 Mode,通常用不到
    第五種模式: kCFRunLoopCommonModes: 這是一個佔位用的Mode,不是一種真正的Mode

  • CFRunloopTimerRef
    (1) runloop一啟動就會選中一種模式,當選中了一種模式之後其它的模式就不會參與。一個mode裡面可以新增多個NSTimer,也就是說以後當建立NSTimer的時候,可以指定它是在什麼模式下執行的。
    (2) 它是基於時間的觸發器,說直白點那就是時間到了我就觸發一個事件,觸發一個操作。基本上說的就是NSTimer .
    (3) 相關程式碼 / - (void)timer2 { //NSTimer 呼叫了scheduledTimer方法,那麼會自動新增到當前的runloop裡面去,而且runloop的執行模式kCFRunLoopDefaultMode

NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
  • CFRunloopSourceRef
    (1)是事件源也就是輸入源,有兩種分類模式;
    一種是按照蘋果官方文件進行劃分的
    另一種是基於函式的呼叫棧來進行劃分的(source0和source1)。
    (2)具體的分類情況

    *以前的分法
    Port-Based Sources
    Custom Input Sources
    Cocoa Perform Selector Sources

    *現在的分法
    Source0:非基於Port的
    Source1:基於Port的

    (3) 可以通過打斷點的方式檢視一個方法的函式呼叫棧

  • CFRunLoopObserverRef
    (1) CFRunLoopObserverRef是觀察者,能夠監聽RunLoop的狀態改變
    (2) 如何監聽

    //建立一個runloop監聽者 CFRunLoopObserverRef observer =
    CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(),kCFRunLoopAllActivities,
    YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
    NSLog(@”監聽runloop狀態改變—%zd”,activity); }); //為runloop新增一個監聽者 CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer,
    kCFRunLoopDefaultMode); CFRelease(observer);

(3)監聽的狀態

typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
kCFRunLoopEntry = (1UL << 0), //即將進入Runloop
kCFRunLoopBeforeTimers = (1UL << 1), //即將處理NSTimer
kCFRunLoopBeforeSources = (1UL << 2), //即將處理Sources
kCFRunLoopBeforeWaiting = (1UL << 5), //即將進入休眠
kCFRunLoopAfterWaiting = (1UL << 6), //剛從休眠中喚醒
kCFRunLoopExit = (1UL << 7), //即將退出runloop
kCFRunLoopAllActivities = 0x0FFFFFFFU //所有狀態改變 };

三.RunLoop執行邏輯

以下是網友整理的執行邏輯圖:
這裡寫圖片描述

通過上圖我們可以做以下執行邏輯的總結:

  1. 一個執行緒對應一個runLoop,主執行緒的runloop是程式一啟動,預設就建立一個runloop,建立好了之後就會給它新增一些預設的模式,每個模式裡面會有很多的 source /timer/observer ,新增好這些模式後,observer就會監聽主執行緒的runloop,進入runloop後,就開始處理事件,先處理timer,再處理source0,source0處理完之後再處理source1,當把這些所有的事件反覆的處理完之後,如果沒有事件了,那麼runloop就會進入睡眠狀態,當用戶又觸發了新的事件,就會喚醒runloop,喚醒runloop後回到第二步,重新處理新的timer,新的source0,新的source1,處理完後就睡眠,一直反覆,當我們把程式關閉或者強退,這個時候observer就會監聽都runloop退出了.

  2. observer是監聽runloop狀態的.

  3. timer / source/
    CFRunLoopRef建立一個timer必須新增到runloop 才會執行,新增的時候要指定模式 defaurce模式 ,不對程式做任何操作 timer就會後臺執行 ,當我進行操作的時候runloop模式就會從預設模式切換到其他模式,假如說我操作scrollerView 它就會從default模式切換到tracking模式
    而roonloop 同一時刻只能執行一種模式.
    當在建立timer時指定 Comment 僅僅是個標記,預設和追蹤,那麼timer就會隨著觸發的模式不同進行 預設和追蹤模式的選擇

  4. Source :source一般是不會去操作的,第一種是基於自定義的,第二種是基於埠的,第三種是基於Performselect的
    通過函式呼叫棧來對source分類:分為source0 source1 :

    • source0是非基於埠的,是使用者自己手動觸發的操作,比如觸控滑動等操作.

    • Source1是系統內部的一些埠觸發的事件

    • 子執行緒的runloop需要手動建立,需要手動開啟

5.自動釋放池,什麼時候建立和釋放 ?
(1)第一次建立:是在runloop進入的時候建立 對應的狀態 = KCFRunLoopEntry
(2)最後一個退出,是在runloop退出的時候 對應的狀態 = KCFRunLoopExit
(3)其他的建立和釋放
每次睡覺的時候會釋放前自動釋放池,再建立一個新的
即將進入睡眠的時候,先釋放上一次建立的自動釋放池,然後再建立一個新的釋放池

相關推薦

iOS開發 底層執行迴圈—— RunLoop

一.RunLoop基本概念 概念:程式的執行迴圈,通俗的來說就是跑圈. 1. 基本作用(作用重大) (1) 保持程式的持續執行(ios程式為什麼能一直活著不會死) (2) 處理app中的各種事件(比如觸控事件、定時器事件【NSTimer】、sel

2018最新精品iOS開發底層進階視頻分享

log 技術 mar pro OS ges roc -o watermark 需要以下視頻的朋友請加我QQ:1499732272 或微信: 2018最新精品iOS開發底層進階視頻分享

ios開發之使用block引發迴圈引用導致記憶體洩露

// // JLPerson.h // BlockTest // // Created by Mac on 15-3-28. // Copyright (c) 2015年 vxinyou. All rights reserved. // #import typedef void (^MyBloc

iOS開發-底層篇-Class詳解,ios底層-class詳解

前言:iOS的開發語言objective-c,它的真實面目是它不是真正的面嚮物件語言,而抽象理解為此而已。其實它就是C+,有個公式可以很好地詮釋那就是 OC = C + Runtime; 接下來我們就好好講講在Runtime下的objc-class。準備資料,objc

IOS開發之延時執行的幾種方法

1.最直接的方法performSelector:withObject:afterDelay: 這種方法的缺點:每次要為延時寫一個方法 2.使用類別,用BOLCK執行 [程式碼]c#/cpp/oc程式碼: 01 @implementation NSObje

iOS開發之關於Runtime執行時:類與物件

Objective-C語言是一門動態語言,它將很多靜態語言在編譯和連結時期做的事放到了執行時來處理。這種動態語言的優勢在於:我們寫程式碼時更具靈活性,如我們可以把訊息轉發給我們想要的物件,或者隨意交換一個方法的實現等。 這種特性意味著Objective-C不僅需要一個編譯器,還需要一個執行時系統

iOS開發底層知識——Runtime詳解

簡介 Runtime 又叫執行時,是一套底層的 C 語言 API,其為 iOS 內部的核心之一,我們平時編寫的 OC 程式碼,底層都是基於它來實現的。比如: [receiver message]; // 底層執行時會被編譯器轉化為: objc_msgSend(receiver, selector) //

iOS開發-使用Runloop實現執行緒保活、執行緒常駐

保證執行緒的長時間存活 在iOS開發過程中,有時一些花費時間比較長的操作阻塞主執行緒,導致介面卡頓,那麼我們就會建立一個子執行緒,然後把這些花費時間比較長的操作放在子執行緒中來處理。可是當子執行緒中的任務執行完畢後,子執行緒就會被銷燬掉。 首先,我們建立一

iOS開發執行緒-RunLoop

一、什麼是RunLoop   1.從字面意思看     1)執行迴圈     2)跑圈   2.基本作用     1)保持程式的持續執行     2)處理App中的各種事件(比如觸控事件、定時器事件、Selector事件)     3)節省CPU資源,提高程式效能:該做事

iOS開發各種底層實現--面試必備!

task 源碼 控件 改變 消息發送 釋放內存 retain select 匹配 iOS開發常用技術底層實現(精簡概述) 本章將對ios開發技術底層實現的總結,其實關於ios開發中各種底層的實現,網上相關文章多到數不過來,而不且非常不錯,我也沒有自信我能比他們做的更好,因

iOS開發多線程-RunLoop

相關 ons glob num 以及 com 開源 agen getc 一、什麽是RunLoop 1.從字面意思看 1)運行循環 2)跑圈 2.基本作用 1)保持程序的持續運行 2)處理App中的各種事件(比如觸摸事件、定時器事

玩轉iOS開發 - Runloop 具體解釋

img mar dsm ews down eas log ada 開發 Runloop 具體解釋

iOS 開發ipa包瘦身 -- 可執行檔案大小

專案寫完以後打出來的包太大 分析一下 首先開啟Products下有個.app 檔案 右鍵show in finder後 再次右鍵 顯示包內容 專案打包後的檔案就會一一羅列在這裡。 這裡重點看一下 這裡有個黑色的可執行檔案,在我專案裡一開始竟然達到了50M+ 那麼這個檔

ios開發網路-大檔案的多執行緒斷點下載

說明:本文介紹多執行緒斷點續傳。專案中使用了蘋果自帶的類,實現了同時開啟多條執行緒下載一個較大的檔案。 因為實現過程較為複雜, 實現思路:下載 開始,建立一個與要下載檔案大小相同的檔案(如果要下載100M,那麼就在沙盒建立一個100M的檔案,然後計算每一段的下載量,開啟多條執行緒下載各段的資料,分

iOS開發(swift):頁面跳轉之設定第一次執行的介面

0.介面回顧   1.在AppDelegate檔案中新增如下程式碼 import UIKit @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate {

Xcode開發ios專案遇到自定義執行時屬性異常

異常包含以下字樣: this class is not key value coding-compliant for the key 原因: 添加了使用者定義的執行時屬性,去檢查一下, 點選報錯對應的控制元件,然後看一下,不需要的刪除,如果是空名稱的更要刪除,例如下圖:

iOS開發執行緒詳解

在iOS開發中,多執行緒開發是非常重要的核心之一,這篇文章和大家分享一下多執行緒的進階-死鎖. iOS有三種多執行緒程式設計的技術,分別是:(一)NSThread(二)Cocoa NSOperation(三)GCD(全稱:Grand Central Dispatch) 如果你對多執行緒

iOS開發執行緒學習總結 - GCD的使用

文章內容和排版參考: iOS 多執行緒: [GCD]詳盡總結 GCD - 核心概念:  任務 | 佇列 任務: 就是指需要執行的程式碼, 在block中編寫,有 同步執行 和 非同步執行 兩種方式. 

【軟體開發底層知識修煉】十 連結器-main函式不是第一個被執行的函式

上一篇文章,大概瞭解了連結器的工作內容就是:符號解析和重定位。點選上一篇文章檢視:點選檢視。 本片文章其實還是圍繞連結器來學習。只不過不是很明顯,當你學到下一篇文章時,就明白了。 本篇文章來弄明白一個問題:在C/C++程式被載入到記憶體中準備執行時,main函式是第一個被執行的函

【軟體開發底層知識修煉】九 連結器-可重定位檔案與可執行檔案

上幾篇文章學習了Binutils輔助工具裡面的幾個實用的工具,那些工具對於以後的學習都是非常有幫助的,尤其是C語、C++語言的學習以及除錯是非常有幫助的。點選連結檢視上一篇文章:點選檢視 本篇文章開始一個新的知識的學習,連結器的學習。學習完連結器的系列文章,我們將全面瞭解連結器的工作