Runtime機制之結構體及操作函數

来源:http://www.cnblogs.com/gzhu-lkun/archive/2016/10/18/5928904.html
-Advertisement-
Play Games

一、動態語言 Objective-C語言是一門動態語言,它將很多靜態語言在編譯和鏈接時期做的事放到了運行時來處理。這種動態語言的優勢在於:具有靈活性,比如:消息轉發,方法交換等。它有一個運行時系統Objc Runtime,其實是一個Runtime庫,基本上是用C和彙編寫的,這個庫使得C語言有了面向對 ...


一、動態語言

Objective-C語言是一門動態語言,它將很多靜態語言在編譯和鏈接時期做的事放到了運行時來處理。這種動態語言的優勢在於:具有靈活性,比如:消息轉發,方法交換等。它有一個運行時系統Objc Runtime,其實是一個Runtime庫,基本上是用C和彙編寫的,這個庫使得C語言有了面向對象的能力。

1. runtime庫主要做下麵兩件事:

  • 封裝:用c語言把對象封裝成基本的數據結構,如:類結構體,對象結構體等。這些結構體和函數被runtime函數封裝後,我們就可以在程式運行時創建,檢查,修改類、對象和它們的方法了。
  • 找出方法的最終執行代碼:把消息機制轉換為函數的調用。

 

二、基本結構體

1. 類結構體:objc_class

  • isa:指向該類對象所屬類(即元類)的指針,根類的元類指向自己
  • super_class:指向父類的指針,根類的父類指針指向NULL
  • name:類名
  • version:版本
  • info:類信息
  • instance_size:改類實例的大小
  • ivars:屬性鏈表
  • methodLists:方法鏈表
  • cache:方法緩存鏈表
  • protocols:協議鏈表

 

typedef struct objc_class *Class;
struct objc_class {
    Class isa  OBJC_ISA_AVAILABILITY;

#if !__OBJC2__
    Class super_class                       OBJC2_UNAVAILABLE;  // 父類
    const char *name                        OBJC2_UNAVAILABLE;  // 類名
    long version                            OBJC2_UNAVAILABLE;  // 類的版本信息,預設為0
    long info                               OBJC2_UNAVAILABLE;  // 類信息,供運行期使用的一些位標識
    long instance_size                      OBJC2_UNAVAILABLE;  // 該類的實例變數大小
    struct objc_ivar_list *ivars            OBJC2_UNAVAILABLE;  // 該類的成員變數鏈表
    struct objc_method_list **methodLists   OBJC2_UNAVAILABLE;  // 方法定義的鏈表
    struct objc_cache *cache                OBJC2_UNAVAILABLE;  // 方法緩存
    struct objc_protocol_list *protocols    OBJC2_UNAVAILABLE;  // 協議鏈表
#endif

} OBJC2_UNAVAILABLE;

 

2. 實例對象結構體:objc_objective 

  • isa:指向所屬類的指針。(僅僅一個指針)

 

typedef struct objc_object *id;

struct objc_object {
    Class isa  OBJC_ISA_AVAILABILITY;
};

 

3. 緩存方法鏈表結構體:objc_cache

  • mask:可緩存方法的數量
  • occupied:已緩存方法的數量
  • buckets:指針數組,存儲的是指針,指向已緩存的方法結構體

 

typedef struct objc_cache *cache;

struct objc_cache {
    unsigned int mask /* total = mask + 1 */                 OBJC2_UNAVAILABLE;
    unsigned int occupied                                    OBJC2_UNAVAILABLE;
    Method buckets[1]                                        OBJC2_UNAVAILABLE;
};

 

4. 元類結構體(類對象所屬類)

  • 同類結構體一樣,只是元類的isa指針都是指向根類NSObject元類,而根類的元類的isa指針指向自己。

我們都知道,實例對象擁有一個指向所屬類的isa指針。那類本身也可以看成是所屬類的對象,即類對象那它自然也擁有一個指向所屬類的isa指針,這個指針指向的也是該類對象的所屬類,即元類。所以,當我們向一個對象發送消息時,runtime會在這個對象所屬的這個類的方法列表中查找方法;而向一個類發送消息時,會在這個類的所屬類,即元類meta-class的方法列表中查找。

 

5. 舉例說明,看看以下代碼如何執行的

NSArray *array = [[NSArray alloc] init];

 

  • runtime庫向類對象NSArray發送了alloc消息,類對象根據isa指針去所屬類,即元類中查找響應的方法
  • 在元類中,先查cache,再查methodLists,由於元類中沒有方法alloc,便根據super_class指針去父類NSObjec中找查找
  • 在父類中,同樣先查cache,再查methodLists,在methodLists找到,立即響應消息
  • 檢測類NSArray中instance_size的大小,根據所需的空間大小分配記憶體
  • 創建objc_objective結構體以及實例變數,把結構體的isa指針指向父類
  • 把alloc方法緩存到自己的cache鏈表中
  • runtime庫又向剛創建好的實例對象發送init消息,對象根據isa指針去所屬類NSArray中查找
  • 先查cache,再查methodLists,查到後則響應
  • 把實例對象中的實例變數初始化
  • 把方法init緩存到cache鏈表中

 

三、類與對象操作函數

1. 類相關操作函數:以class為首碼命名

  • class_getName                          // 獲取類名
  • class_getSuperclass                       // 獲取父類
  • class_isMetaClass                          // 判斷類是不是元類
  • class_getInstanceSize                    // 獲取實例大小
  • class_getInstanceVariable              // 獲取實例成員變數
  • class_getClassVariable                   // 獲取類成員變數
  • class_addIvar                                // 添加實例變數
  • class_copyIvarList                         // 獲取整個成員變數表
  • class_getProperty                         // 獲取指定屬性
  • class_copyPropertyList                  // 獲取整個屬性表
  • class_addProperty                         // 添加屬性
  • class_replaceProperty                   // 替換屬性
  • class_addMethod                         // 添加方法
  • class_getInstanceMethod             // 獲取實例方法
  • class_getClassMethod                  // 獲取類方法
  • class_copyMethodList                  // 獲取所有方法的數組
  • class_replaceMethod                   // 替代方法的實現
  • class_getMethodImplementation  // 返回方法的具體實現
  • class_respondsToSelector            // 類實例是否響應指定的selector
  • class_addProtocol                       // 添加協議
  • class_conformsToProtocol            // 返回類是否實現指定的協議
  • class_copyProtocolList                 // 返回類實現的協議列表
  • class_getVersion                         // 獲取版本號
  • class_setVersion                         // 設置版本號

 

    • 父類和元類
// 獲取類的父類
Class class_getSuperclass ( Class cls );

// 判斷給定的Class是否是一個元類
BOOL class_isMetaClass ( Class cls );

 

    •  類名  
// 獲取類的類名
const char * class_getName ( Class cls );

 

    • 成員變數大小  
// 獲取實例大小
size_t class_getInstanceSize ( Class cls );

 

    • 版本  
// 獲取版本號
int class_getVersion ( Class cls );

// 設置版本號
void class_setVersion ( Class cls, int version );

 

    • 成員變數  
/** 成員變數操作函數 */


//
獲取類中指定名稱實例成員變數的信息 Ivar class_getInstanceVariable ( Class cls, const char *name ); // 獲取類成員變數的信息 Ivar class_getClassVariable ( Class cls, const char *name ); // 添加成員變數 BOOL class_addIvar ( Class cls, const char *name, size_t size, uint8_t alignment, const char *types ); // 獲取整個成員變數列表 Ivar * class_copyIvarList ( Class cls, unsigned int *outCount );

 

    •   屬性 
/** 屬性操作函數 */


// 獲取指定的屬性
objc_property_t class_getProperty ( Class cls, const char *name );

// 獲取屬性列表
objc_property_t * class_copyPropertyList ( Class cls, unsigned int *outCount );

// 為類添加屬性
BOOL class_addProperty ( Class cls, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount );

// 替換類的屬性
void class_replaceProperty ( Class cls, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount );

 

    • 方法  
// 添加方法
BOOL class_addMethod ( Class cls, SEL name, IMP imp, const char *types );

// 獲取實例方法
Method class_getInstanceMethod ( Class cls, SEL name );

// 獲取類方法
Method class_getClassMethod ( Class cls, SEL name );

// 獲取所有方法的數組
Method * class_copyMethodList ( Class cls, unsigned int *outCount );

// 替代方法的實現
IMP class_replaceMethod ( Class cls, SEL name, IMP imp, const char *types );

// 返回方法的具體實現
IMP class_getMethodImplementation ( Class cls, SEL name );
IMP class_getMethodImplementation_stret ( Class cls, SEL name );

// 類實例是否響應指定的selector
BOOL class_respondsToSelector ( Class cls, SEL sel );

 

    • 協議  
// 添加協議
BOOL class_addProtocol ( Class cls, Protocol *protocol );

// 返回類是否實現指定的協議
BOOL class_conformsToProtocol ( Class cls, Protocol *protocol );

// 返回類實現的協議列表
Protocol * class_copyProtocolList ( Class cls, unsigned int *outCount );

 

2. 對象相關的操作函數,以object為首碼命名

  • object_copy                                    // 返回指定對象的一份拷貝
  • object_dispose                                // 釋放指定對象占用的記憶體
  • object_setInstanceVariable              // 修改類實例的實例變數的值
  • object_getInstanceVariable              // 獲取對象實例變數的值
  • object_getIndexedIvars                   // 返回指向給定對象分配的任何額外位元組的指針
  • object_getIvar                                // 返回對象中實例變數的值
  • object_setIvar                                // 設置對象中實例變數的值
  • object_getClassName                      // 返回給定對象的類名
  • object_getClass                              // 返回對象的類
  • object_setClass                              // 設置對象的類

 

    •   針對整個對象進行操作的函數
// 返回指定對象的一份拷貝
id object_copy ( id obj, size_t size );

// 釋放指定對象占用的記憶體
id object_dispose ( id obj );

 

 

    •   針對對象實例變數進行操作的函數
// 修改類實例的實例變數的值
Ivar object_setInstanceVariable ( id obj, const char *name, void *value );

// 獲取對象實例變數的值
Ivar object_getInstanceVariable ( id obj, const char *name, void **outValue );

// 返回指向給定對象分配的任何額外位元組的指針
void * object_getIndexedIvars ( id obj );

// 返回對象中實例變數的值
id object_getIvar ( id obj, Ivar ivar );

// 設置對象中實例變數的值
void object_setIvar ( id obj, Ivar ivar, id value );

 

 

    •   針對對象的類進行操作的函數
// 返回給定對象的類名
const char * object_getClassName ( id obj );

// 返回對象的類
Class object_getClass ( id obj );

// 設置對象的類
Class object_setClass ( id obj, Class cls );

 

四、動態創建類和對象 

1. 動態創建類

 

  • objc_allocateClassPair  // 創建一個新類和元類
  • objc_disposeClassPair  // 銷毀一個類及其相關聯的類
  • objc_registerClassPair // 在應用中註冊由objc_allocateClassPair創建的類

 

// 創建一個新類和元類
Class objc_allocateClassPair ( Class superclass, const char *name, size_t extraBytes );

// 銷毀一個類及其相關聯的類
void objc_disposeClassPair ( Class cls );

// 在應用中註冊由objc_allocateClassPair創建的類
void objc_registerClassPair ( Class cls );

 

 

2. 動態創建對象

  • class_createInstance       // 創建類實例
  • objc_constructInstance   // 在指定位置創建類實例
  • objc_destructInstance    // 銷毀類實例

 

// 創建類實例
id class_createInstance ( Class cls, size_t extraBytes );

// 在指定位置創建類實例
id objc_constructInstance ( Class cls, void *bytes );

// 銷毀類實例
void * objc_destructInstance ( id obj );

 

 

五、獲取類定義

 1. Objective-C動態運行庫會自動註冊我們代碼中定義的所有的類。我們也可以在運行時創建類定義並使用objc_addClass函數來註冊它們。

// 獲取已註冊的類定義的列表
int objc_getClassList ( Class *buffer, int bufferCount );

// 創建並返回一個指向所有已註冊類的指針列表
Class * objc_copyClassList ( unsigned int *outCount );

// 返回指定類的類定義
Class objc_lookUpClass ( const char *name );
Class objc_getClass ( const char *name );
Class objc_getRequiredClass ( const char *name );

// 返回指定類的元類
Class objc_getMetaClass ( const char *name );

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 為.net core 配一個基於html5的UI框架 傳送門:TchApp項目說明 ...
  • [ASP.NET Core] Getting Started 前言 本篇文章介紹如何快速建立一個ASP.NET Core應用程式,為自己留個紀錄也希望能幫助到有需要的開發人員。 ASP.NET Core官網 環境 建立一個ASP.NET Core應用程式,首先要從官網下載SDK來建置.NET Cor ...
  • 枚舉類型是定義了一組“符號名稱/值”配對。枚舉類型是強類型的。每個枚舉類型都是從system.Enum派生,又從system.ValueType派生,而system.ValueType又從system.Object派生,所以枚舉類型是指類型。 編譯枚舉類型時,C#編譯器會把每個符號轉換成類型的一個常 ...
  • 上一章我們講到關於C#線程方向的應用。但是筆者並沒有講到多線程中的另一個知識點——同步。多線程的應用開發都有可能發生臟數據。同步的功能或多或少都會用到。本章就要來講一下關於線程同步的問題。根據筆者這幾年來的.NET開發可以瞭解到的同步方式至少有四種以上。如。lock、volatile、Monitor ...
  • VS中如何快捷地給自己的代碼添加創建信息註釋 Intro 以下討論的都是沒有使用 GIT 來管理源代碼的情況,如果使用 GIT 管理源代碼可直接使用VS的Git擴展就不需要考慮以下問題。 什麼是創建信息註釋? 創建信息註釋,類似於文件的創建信息,一般來說,至少要有創建人和創建時間。如果說有人修改了方 ...
  • spring的事務處理分為兩種: 1、編程式事務:在程式中控制事務開始,執行和提交;(不建議使用,所以這裡我就不說明太多) 2、聲明式事務:在Spring配置文件中對事務進行配置,無須在程式中寫代碼;(建議使用) 我對”聲明式“的理解是這樣的:Spring配置文件中定義好了這樣一個規則, 這個規則可 ...
  • 回到目錄 挺有意思的一件事 對於MVC視圖渲染來說,大家應該不會陌生,但對於模型的渲染,不知道是否聽說過,主要是說Model通過它屬性的相關特性(DataType,UIHint)來將它們自動渲染到View上,這是一個比較不錯的技術,因為使用傳統的Html.EditorForModel去渲染是不能滿足 ...
  • 需求分析 ”null exception“很見的一種異常,但在某些情況下卻會引起嚴重的bug! 本文目的就是對代碼進行null 的檢查,避免不應該出現的Error。 本文藉助reshaper,全局檢測項目中所有可能出現的null exception 關於resharper的知識:http://zzk ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...