蘋果iOS開發深入淺出Cocoa之類與物件

2021-09-01 08:20:28 字數 3526 閱讀 4510

from:

。從**入手呢?那當然是最基本的類與物件。與c++相比,objc中的類與物件結構要簡潔與一致得多(參考《深度探索c++物件模型》,你就知道c++中類與物件結構的複雜)。本文將詳細講解objc中類與物件的結構,下回將講如何在 runtime 時操作類。

我們可以在/usr/include/objc/objc.h 和 runtime.h 中找到對 class 與 object 的定義:

typedef struct objc_class *class;

typedef struct objc_object *id;

class 是乙個 objc_class 結構型別的指標;而 id(任意物件) 是乙個 objc_object 結構型別的指標,其第乙個成員是乙個 objc_class 結構型別的指標。注意這裡有一關鍵的引申解讀:記憶體布局以乙個 objc_class 指標為開始的所有東東都可以當做乙個 object 來對待! 那 objc_class 又是怎樣乙個結構體呢?且看:

struct objc_class

objc_class 結構體的各成員介紹如下:

isa:是乙個 objc_class 型別的指標,看到這裡,想起我前面的引申解讀了沒?記憶體布局以乙個 objc_class 指標為開始的所有東東都可以當做乙個 object 來對待! 這就是說 objc_class 或者說類其實也可以當做乙個 objc_object 物件來對待!物件是物件,類也是物件,是不是有點混淆?別急,objc發明(or 重用)了乙個術語來區分這兩種不同的物件:類物件(class object)與例項物件(instance object)。ok,名稱混淆的問題解決,下面我將使用這兩個術語來區分不同的物件,而使用「物件」這一術語來泛指所有的物件。objc還對類物件與例項物件中的 isa 所指向的類結構作了不同的命名:類物件中的 isa 指向類結構被稱作 metaclass,metaclass 儲存類的static類成員變數與static類成員方法(+開頭的方法);例項物件中的 isa 指向類結構稱作 class(普通的),class 結構儲存類的普通成員變數與普通成員方法(-開頭的方法)。

super_class:一看就明白,指向該類的父類唄!如果該類已經是最頂層的根類(如 nsobject 或 nsproxy),那麼 super_class 就為 null。

好,先中斷一下其他類結構成員的介紹,讓我們釐清一下在繼承層次中,子類,父類,根類(這些都是普通 class)以及其對應的 metaclass 的 isa 與 super_class 之間關係:

規則一:類的例項物件的 isa 指向該類;該類的 isa 指向該類的 metaclass;

規則二:類的 super_class 指向其父類,如果該類為根類則值為 null;

規則三:metaclass 的 isa 指向根 metaclass,如果該 metaclass 是根 metaclass 則指向自身;

規則四:metaclass 的 super_class 指向父 metaclass,如果該 metaclass 是根 metaclass 則指向該 metaclass 對應的類;

好吧,文字總是那麼乏力,有圖有真相!

那麼 class 與 metaclass 有什麼區別呢?

class 是 instance object 的類型別。當我們向例項物件傳送訊息(例項方法)時,我們在該例項物件的 class 結構的 methodlists 中去查詢響應的函式,如果沒找到匹配的響應函式則在該 class 的父類中的 methodlists 去查詢(查詢鏈為上圖的中間那一排)。如下面的**中,向str 例項物件傳送 lowercasestring 訊息,會在 nsstring 類結構的 methodlists 中去查詢 lowercasestring 的響應函式。

nsstring * str;[str lowercasestring];

metaclass 是 class object 的類型別。當我們向類物件傳送訊息(類方法)時,我們在該類物件的 metaclass 結構的 methodlists 中去查詢響應的函式,如果沒有找到匹配的響應函式則在該 metaclass 的父類中的 methodlists 去查詢(查詢鏈為上圖的最右邊那一排)。如下面的**中,向 nsstring 類物件傳送 stringwithstring 訊息,會在 nsstring 的 metaclass 類結構的 methodlists 中去查詢 stringwithstring 的響應函式。

[nsstring stringwithstring:@"str"];

好,至此我們明白了類的結構層次,讓我們接著看類結構中的其他成員。

name:乙個 c 字串,指示類的名稱。我們可以在執行期,通過這個名稱查詢到該類(通過:id objc_getclass(const char *aclassname))或該類的 metaclass(id objc_getmetaclass(const char *aclassname));

version:類的版本資訊,預設初始化為 0。我們可以在執行期對其進行修改(class_setversion)或獲取(class_getversion)。

cls_class (0x1l) 表示該類為普通 class ,其中包含例項方法和變數;

cls_meta (0x2l) 表示該類為 metaclass,其中包含類方法;

cls_initialized (0x4l) 表示該類已經被執行期初始化了,這個標識位只被 objc_addclass 所設定;

cls_posing (0x8l) 表示該類被 pose 成其他的類;(poseclass 在objc 2.0中被廢棄了);

cls_flush_cache (0x20l) 為objc執行期所使用

cls_grow_cache (0x40l) 為objc執行期所使用

cls_need_bind (0x80l) 為objc執行期所使用

cls_method_array (0x100l) 該標誌位指示 methodlists 是指向乙個 objc_method_list 還是乙個包含 objc_method_list 指標的陣列;

instance_size:該類的例項變數大小(包括從父類繼承下來的例項變數);

methodlists:與 info 的一些標誌位有關,cls_method_array 標識位決定其指向的東西(是指向單個 objc_method_list還是乙個 objc_method_list 指標陣列),如果 info 設定了 cls_class 則 objc_method_list 儲存例項方法,如果設定的是 cls_meta 則儲存類方法;

cache:指向 objc_cache 的指標,用來快取最近使用的方法,以提高效率;

protocols:指向 objc_protocol_list 的指標,儲存該類宣告要遵守的正式協議。

總結:

objc 為每個類的定義生成兩個 objc_class ,乙個即普通的 class,另乙個即 metaclass。我們可以在執行期建立這兩個 objc_class 資料結構,然後使用 objc_addclass 動態地建立新的類定義。這個夠動態夠強大的吧?下回講演示如何在執行期動態建立新類。

深入淺出gstreamer開發

gstreamer 解決什麼問題?上層介面和應用方式的 相對穩定 與底層介面 平台環境的 多樣化。例如 codec 通用元件不靈活與需求的多變。色彩空間轉換 縮放 編譯碼等元件功能是單一的。通過對這些元件進行組合,就可以滿足多變的需求。要想擁有模組性 可移植性和通用的功能,通常是以極高的複雜性為代價...

深入淺出gstreamer開發

gstreamer 解決什麼問題?上層介面和應用方式的 相對穩定與底層介面 平台環境的 通用元件不靈活與需求的多變。色彩空間轉換 縮放 編譯碼等元件功能是單一的。通過對這些元件進行組合,就可以滿足多變的需求。要想擁有模組性 可移植性和通用的功能,通常是以極高的複雜性為代價。計算機系統的萬能解決辦法 ...

深入淺出 模組開發

abp本身是乙個包含許多nuget包的模組化框架。它還提供了乙個完整的基礎架構來開發你自己的具有實體 服務 資料庫整合 api ui元件等等功能的應用程式模組。每個模組都應該定義乙個模組類.定義模組類的最簡單方法是建立乙個派生自abpmodule的類,如下所示 public class blogmo...