深入理解Objective-C的Runtime機制

2020-12-25 CSDN技術社區

Objective-C是基於C語言加入了面向對象特性和消息轉發機制的動態語言,這意味著它不僅需要一個編譯器,還需要Runtime系統來動態創建類和對象,進行消息發送和轉發。下面通過分析Apple開源的Runtime代碼(我使用的版本是objc4-646.tar)來深入理解Objective-C的Runtime機制。

Runtime數據結構

在Objective-C中,使用[receiver message]語法並不會馬上執行receiver對象的message方法的代碼,而是向receiver發送一條message消息,這條消息可能由receiver來處理,也可能由轉發給其他對象來處理,也有可能假裝沒有接收到這條消息而沒有處理。其實[receiver message]被編譯器轉化為:

id objc_msgSend ( id self, SEL op, ... );

下面從兩個數據結構id和SEL來逐步分析和理解Runtime有哪些重要的數據結構。

SEL

SEL是函數objc_msgSend第二個參數的數據類型,表示方法選擇器,按下面路徑打開objc.h文件:

SEL Data Structure

查看到SEL數據結構如下:

typedef struct objc_selector *SEL;

其實它就是映射到方法的C字符串,你可以通過Objc編譯器命令@selector()或者Runtime系統的sel_registerName函數來獲取一個SEL類型的方法選擇器。

如果你知道selector對應的方法名是什麼,可以通過NSString* NSStringFromSelector(SEL aSelector)方法將SEL轉化為字符串,再用NSLog列印。

id

接下來看objc_msgSend第一個參數的數據類型id,id是通用類型指針,能夠表示任何對象。按下面路徑打開objc.h文件:

id Data Structure

查看到id數據結構如下:

/// Represents an instance of a class.struct objc_object { Class isa OBJC_ISA_AVAILABILITY;};/// A pointer to an instance of a class.typedef struct objc_object *id;

id其實就是一個指向objc_object結構體指針,它包含一個Class isa成員,根據isa指針就可以順藤摸瓜找到對象所屬的類。

注意:根據Apple的官方文檔Key-Value Observing Implementation Details提及,key-value observing是使用isa-swizzling的技術實現的,isa指針在運行時被修改,指向一個中間類而不是真正的類。所以,你不應該使用isa指針來確定類的關係,而是使用class方法來確定實例對象的類。

Class

isa指針的數據類型是Class,Class表示對象所屬的類,按下面路徑打開objc.h文件:


Class Data Structure

/// An opaque type that represents an Objective-C class.typedef struct objc_class *Class;

可以查看到Class其實就是一個objc_class結構體指針,但這個頭文件找不到它的定義,需要在runtime.h才能找到objc_class結構體的定義。

按下面路徑打開runtime.h文件:

objc_class Data Structure

相關焦點

  • Objective-C 與 Runtime:為什麼是這樣?
    來自:springox的博客連結:http://springox.w18.net/2015/09/03/objectivecruntime
  • Runtime那些事兒(消息機制)
    之前在項目中有遇到過用runtime解決改變全局字體的問題,所以再一次感受到了runtime黑魔法的強大,趁現在有機會分享一下對runtime的一些理解。在對象調用方法是Objective-C中經常使用的功能,也就是消息的傳遞,而Objective-C是C的超集,所以和C不同的是,Objective-C使用的是動態綁定,也就是runtime。Objective-C的消息傳遞和消息機制也就不多說了,今天主要說的是動態方法,也就是函數的調用。
  • 深入理解Object-C消息轉發機制
    /相信大家對Object-C的消息傳遞機制並不陌生(如果不熟悉,我後續會再寫一篇關於消息傳遞機制的文章),今天我來講解另外一個重要的問題,就是對象在收到無法解讀的消息之後會發生什麼情況。若想令類能理解某條消息,我們必須以程序碼實現出對應的方法才行。但是,在編譯器向類發送了其無法解讀的消息並不會報錯,因為在運行期可以繼續向類中添加方法(動態添加),所以編譯器在編譯時還無法確知類中到底會不會有某個方法實現。當對象接收到無法解讀的消息後,就會啟動「消息轉發」(message forwarding)機制,程式設計師可經由此過程告訴對象應該如何處理未知消息。
  • 談Runtime機制和使用的整體化梳理
    學習流程圖一.基本概念RunTime簡稱運行時,就是系統在運行的時候的一些機制,其中最主要的是消息機制。對於C語言,函數的調用在編譯的時候會決定調用哪個函數( C語言的函數調用請看這裡 )。編譯完成之後直接順序執行,無任何二義性。OC的函數調用成為消息發送。屬於動態調用過程。
  • runtime是什麼
    什麼是runtime在windows上安裝或執行程序,都有機會遇到詞彙——runtime。CRT(C runtime library)Microsoft Access 2016 Runtimemicrosoft visual c++ runtime libraryC RuntimeVisual C++ 2008 Runtime.NET Common Language Runtimeruntime
  • Objective-C 和 Swift 面試題
    閉包就是沒有名字的函數,或者理解為指向函數的指針。3. 請說明並比較以下關鍵詞:atomatic, nonatomicatomic修飾的對象會保證setter和getter的完整性,任何線程對其訪問都可以得到一個完整的初始化後的對象。因為要保證操作完成,所以速度慢。
  • 深入理解.NET Core的基元(二) - 共享框架
    .NET Core的基元(二) - 共享框架 作者:Lamond Lu本篇是之前翻譯過的《深入理解.NET Core的基元: deps.json, runtimeconfig.json, dll文件[2]》的後續,這個系列作者暫時只寫了3篇,雖然有一些內容和.NET Core 3.0已經不兼容了,但是大部分的原理還都是相通的,所以後面的第三篇我也會翻譯。
  • 深入理解 Go 語言 defer
    defer 估計是每個 Gopher 每天寫代碼都會寫,那麼你是不是真正的理解了 defer 呢?不妨看一下下面這個代碼片段,這個是我之前給 UC 那邊一個 team 做 Golang 培訓的時候想的例子。
  • 這些年我們愛著的 Objective-C
    動態語義是通過一個library來實現的,這個library逐漸發展成了現在的runtime library(簡稱 runtime)。後來Stepstone被Steve Jobs領導的NeXT收購,Objective-C由此迎來它的首次發展。不過NeXT並沒有在語言中引入新特性,而是對runtime做了一些優化,即NeXT runtime。
  • 這些年我們愛著的Objective-C
    動態語義是通過一個library來實現的,這個library逐漸發展成了現在的runtime library(簡稱 runtime)。後來Stepstone被Steve Jobs領導的NeXT收購,Objective-C由此迎來它的首次發展。不過NeXT並沒有在語言中引入新特性,而是對runtime做了一些優化,即NeXT runtime。
  • 在 Flutter 中玩轉 Objective-C Block
    ,24小時後恢復原價若想直接學習課程,掃碼學習(以下內容為正文)作者 | 楊蕭玉 來源 | 玉令天下的博客dart_native 作為一條比 Channel 性能更高開發成本更低的超級通道,通過 C++ 調用 Native 的 API,
  • 10個Objective-C基礎面試題,iOS面試必備
    objective-c – 類裡面的方法只有兩種, 靜態方法和實例方法. 這似乎就不是完整的面向對象了,按照OO的原則就是一個對象只暴露有用的東西. 如果沒有了私有方法的話, 對於一些小範圍的代碼重用就不那麼順手了.
  • 雜談App Store 之 HIG 與 Objective-C
    Modern objc比objc 1.0進步了非常多,所以初學者看書的時候,一定不要走彎路,直接學Modern objc和ARC即可。不過我強烈建議把MRC完全理解透徹,否則會死得很慘。ARC可不是GC,一個是compiler支持,另外一個是runtime支持,完全不一樣的。
  • Objective-C 裡的 eval
    實際上調用任意原生 Objective-C 方法是允許的,訣竅就是使用這個叫 FUNCTION() 的函數,基本等價於 objc_msgSend 或者 performSelector:。iOS 上的代碼籤名政策非常嚴格,默認情況下應用都通過 AppStore 分發,並且有審核機制。蘋果嚴令禁止應用從遠端伺服器動態拉取代碼執行,因為這可能繞過審核機制,實現違反應用規範的功能,甚至分發惡意代碼。
  • 從零開始入門 K8s | 理解 RuntimeClass 與使用多容器運行時
    YAML 文件包含兩個部分:上部分負責創建一個名字叫 runv 的 RuntimeClass 對象,下部分負責創建一個 Pod,該Pod 通過 spec.runtimeClassName 引用了 runv 這個 RuntimeClass。RuntimeClass 對象中比較核心的是 handler,它表示一個接收創建容器請求的程序,同時也對應一個容器運行時。
  • Objective-C中一種消息處理方法performSelector: withObject:
    所以Objective-C可以在runtime的時候傳遞人和消息。   首先介紹兩個方法 SEL和@selector 根據AppleObjective-C Runtime Reference官方文檔這個傳遞消息的函數就是 id objc_msgSend(id theReceiver, SEL theSelector
  • 方舟編譯器 Toy Runtime 可以運行 Hello World 了
    方舟編譯器 runtime 參考實現 pacific 發布了 0.1 版本,支持運行基於方舟編譯器的 Hello World 程序。據了解,pacific 是目前業內首個方舟編譯器 runtime 實現,「實現了從 0 到 1 的一個跨越」。
  • Swift和Objective-C混編
    @objc(Color)enum Цвет: Int {    @objc(Red)    case Красный      @objc(Black)    case Черный} @objc(Squirrel)class Белка: NSObject {    @objc(color)
  • Custom Runtime - 打破雲函數語言限制
    - 關於runtime的拓展性。舉個慄子, 現有SCF java語言環境是java8, 如果用戶想要在SCF中使用JDK11或者更新的JDK15,有沒有辦法解決呢? - 使用成本。用戶語言runtime(可選): 針對解釋型語言,或者說需要runtime來運行的語言,比如js, python, dotnet等,需要用戶提供自己的runtime,並在bootstrap中提供相應的啟動runtime的命令。
  • 深入理解圖注意力機制(Graph Attention Network)
    作為一種代表性的圖卷積網絡,Graph Attention Network (GAT) 引入了注意力機制來實現更好的鄰居聚合。通過學習鄰居的權重,GAT 可以實現對鄰居的加權聚合。因此,GAT 不僅對於噪音鄰居較為魯棒,注意力機制也賦予了模型一定的可解釋性。下圖概述了 Graph Attention Network 主要做的事情。