Runtimes 基礎

1. Runtimes概念

OC 是一門動態(tài)語言,他不僅需要編譯器,還需要運行時系統(tǒng)進行代碼編譯.Runtimes 就執(zhí)行了這個運行時系統(tǒng)代碼編譯工作.
Runtime就是運行時,是Apple用C和匯編語言編寫的一套C語言的API,它正是 Objective-C這門動態(tài)語言的核心。計算機唯一能識別的語言是機器語言,高級編程語言需要先編譯為匯編語言,再由匯編語言編譯為機器語言才能被計算機識別。而 Objective-C語言不能被直接編譯為匯編語言,它必須先編譯為C語言,然后再編譯為匯編語言。而Runtime正是編譯器將我們寫的 Objective-C代碼編譯為C語言時用到的核心庫。
C語言,靜態(tài)語言,在編譯階段就要決定調用哪些函數(shù)屬性,如果函數(shù)未實現(xiàn)就會編譯報錯。
OC語言,動態(tài)語言,在編譯階段并不能決定真正調用哪些函數(shù),只要函數(shù)聲明過即使沒有實現(xiàn)也不會報錯。

2. 消息機制的基本原理

OC 中 方法調用都是類似 [receiver selector]; 的形式,其本質就是讓對象在運行時發(fā)送消息的過程。
[receiver selector]; 在編譯階段與運行階段分別作了什么
編譯階段:[receiver selector]; 方法被編譯器轉換為:
objc_msgSend(receiver,selector) (不帶參數(shù))
objc_msgSend(recevier,selector,org1,org2,…)(帶參數(shù))
運行時階段:消息接受者 recevier 尋找對應的 selector。
通過 recevier 的 isa 指針 找到 recevier 的 Class(類);
在 Class(類) 的 cache(方法緩存) 的散列表中尋找對應的 IMP(方法實現(xiàn));
如果在 cache(方法緩存) 中沒有找到對應的 IMP(方法實現(xiàn)) 的話,就繼續(xù)在 Class(類) 的 method list(方法列表) 中找對應的 selector,如果找到,填充到 cache(方法緩存) 中,并返回 selector;
如果在 Class(類) 中沒有找到這個 selector,就繼續(xù)在它的 superClass(父類)中尋找;
一旦找到對應的 selector,直接執(zhí)行 recevier 對應 selector 方法實現(xiàn)的 IMP(方法實現(xiàn))。
若找不到對應的 selector,消息被轉發(fā)或者臨時向 recevier 添加這個 selector 對應的實現(xiàn)方法,否則就會發(fā)生崩潰。
在上述過程中涉及了好幾個新的概念:objc_msgSend、isa 指針、Class(類)、IMP(方法實現(xiàn)) 等,下面我們來具體講解一下各個概念的含義。

3. Runtime 用來做什么

3.1 基本作用

1.工程基本功能調用
2.在程序運行過程中,動態(tài)的創(chuàng)建類,動態(tài)添加、修改這個類的屬性和方法;
3.遍歷一個類中所有的成員變量、屬性、以及所有方法
4.消息傳遞、轉發(fā)

3.1 項目中的典型用法

1.給系統(tǒng)分類添加屬性、方法 objc_setAssociatedObject()
2.方法交換 (Method Swizzling)
3.獲取對象的屬性、私有屬性
4.字典轉換模型 yymodel
5.KVC、KVO
6.歸檔(編碼、解碼)
7.NSClassFromString class<->字符串
8.消息轉發(fā)

4. Runtime 相關概念

1.isa Class對象,指向objc_class結構體的指針,也就是這個Class的MetaClass(元類)

  • 類的實例對象的 isa 指向該類;該類的 isa 指向該類的 MetaClass
  • MetaCalss的isa對象指向RootMetaCalss
  • 如果MetaClass是RootMetaCalss,那么該MetaClass的isa指針指向它自己
    1.super_class Class對象指向父類對象
  • 如果該類的對象已經是RootClass,那么這個super_class指向nil
  • MetaCalss的SuperClass指向父類的MetaCalss
  • MetaCalss是RootMetaCalss,那么該MetaClass的SuperClass指向該對象的RootClass

經典示意圖

image.png
  • ivars 類中所有屬性的列表,使用場景:我們在字典轉換成模型的時候需要用到這個列表找到屬性的名稱,去取字典中的值,KVC賦值,或者直接Runtime賦值

  • methodLists 類中所有的方法的列表,類中所有方法的列表,使用場景:如在程序中寫好方法,通過外部獲取到方法名稱字符串,然后通過這個字符串得到方法,從而達到外部控制App已知方法。

  • cache 主要用于緩存常用方法列表,每個類中有很多方法,我平時不用的方法也會在里面,每次運行一個方法,都要去methodLists遍歷得到方法,如果類的方法不多還行,但是基本的類中都會有很多方法,這樣勢必會影響程序的運行效率,所以cache在這里就會被用上,當我們使用這個類的方法時先判斷cache是否為空,為空從methodLists找到調用,并保存到cache,不為空先從cache中找方法,如果找不到在去methodLists,這樣提高了程序方法的運行效率

  • protocols 故名思義,這個類中都遵守了哪些協(xié)議,使用場景:判斷類是否遵守了某個協(xié)議上

5.Runtime消息機制

  1. 消息發(fā)送
  • 找到方法 -->調用方法 -->方法回調
  • 首先消息發(fā)動給對象,遍歷對象結構體的methodLists,找到對象響應的方法實現(xiàn),如果沒有就向上查找其父類的方法列表,一單找到就會調用方法,將接受對象的指針傳給他
  • cache 在進行列表查詢時總是很消耗時間的,所以添加了方法cache的概念 將剛剛使用的方法,常用的方法加入cache中,提高方法尋找速度.

6.Runtime消息轉發(fā)

在使用過程中當5中的方法不能再方法列表中找到的時候,就會報錯,拋出異常,
提示找不到方法實現(xiàn)

解決方案
1.實現(xiàn)方法,需要寫代碼主動實現(xiàn)代碼

2.runtime轉發(fā),找不到方法來實現(xiàn),那我們就換發(fā)方法來實現(xiàn)吧

  • 方法找不到實現(xiàn)方法時會調用該函數(shù),
    +(BOOL)resolveInstanceMethod:(SEL)sel 實例方法解析
    +(BOOL)resolveClassMethod:(SEL)sel 類方法解析

  • 消息轉發(fā)第一次方法解析中沒有處理方法將會調用
    -(id)forwardingTargetForSelector:(SEL)aSelector
    將未知SEL作為參數(shù)傳入,尋找另外對象處理,如果可以處理,返回該對象

  • 當我們在前面兩個步驟都沒有處理該未知SEL時,就會到第三個步驟
    -(void)doesNotRecognizeSelector:(SEL)aSelector

  • 如果第三步也沒能實現(xiàn)
    (void)doesNotRecognizeSelector:(SEL)aSelector
    調用崩潰

  • 流程圖


    image.png

7.Runtime消息機制使用

1.分類添加屬性
核心代碼 手動實現(xiàn)get 與set方法

  • (void)setName:(NSString *)name {
    objc_setAssociatedObject(self, &nameKey, name, OBJC_ASSOCIATION_COPY);
    }
  • (NSString *)name {
    return objc_getAssociatedObject(self, &nameKey);
    }
    2.Method Swizzling 方法交換
    這是runtime的靈魂所在 , B哥一點 這可以當做簡單的代碼HOOK
    甲方
    BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types)
    減方法
    class_replaceMethod(Class _Nullable cls, SEL _Nonnull name, IMP _Nonnull imp,
    const char * _Nullable types)
    方法交換
    method_exchangeImplementations(Method _Nonnull m1, Method _Nonnull m2)

原有被交換方法
Method originalMethod = class_getInstanceMethod(class, originalSelector);

要交換的分類新方法
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);

class_replaceMethod(class,swizzledSelector,method_getImplementation(originalMethod),method_getTypeEncoding(originalMethod));

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 我們常常會聽說 Objective-C 是一門動態(tài)語言,那么這個「動態(tài)」表現(xiàn)在哪呢?我想最主要的表現(xiàn)就是 Obje...
    Ethan_Struggle閱讀 2,333評論 0 7
  • 本文轉載自:http://yulingtianxia.com/blog/2014/11/05/objective-...
    ant_flex閱讀 886評論 0 1
  • 本文詳細整理了 Cocoa 的 Runtime 系統(tǒng)的知識,它使得 Objective-C 如虎添翼,具備了靈活的...
    lylaut閱讀 866評論 0 4
  • 繼上Runtime梳理(四) 通過前面的學習,我們了解到Objective-C的動態(tài)特性:Objective-C不...
    小名一峰閱讀 847評論 0 3
  • 關于OC中的消息發(fā)送的實現(xiàn),在去年也看過一次,當時有點不太理解,但是今年再看卻很容易理解。 我想這跟知識體系的構建...
    咖啡綠茶1991閱讀 1,071評論 0 1

友情鏈接更多精彩內容