904
技術社區[雲棲]
iOS開發中的對象係統基礎
[0] Outline
-- [1] id和Class
-- [2] 動態地操作類
-- [3] 實例化
[1] id和Class
在Objective-C中有一個特別的數據類型作為對象標識符:id,可以指向任何類型的對象。
通過 “可以指向任何類型的對象” 這一描述,猜想id實際上是指向Objective-C對象係統中的基類(繼承體係中的祖先結構)的指針,在運行時是指向對象內存布局的基類部分。
第一眼看到id數據類型,我聯想到了Python中的PyObject結構:
typedef struct _object { int ob_refcnt; struct _typeobject *ob_type; } PyObject;
該數據類型也是Python對象係統中的祖先類型,不過與id相對應的應該是PyObject *類型。
id數據類型是一個指向struct objc_object結構的指針:
typedef struct objc_class *Class; typedef struct objc_object { Class isa; } *id;
更確切地說,id是指向Class類型的指針,而Class又是指向struct objc_class結構的指針:
struct objc_class { struct objc_class *isa; struct objc_class *super_class; const char *name; long version; long info; long instance_size; struct objc_ivar_list *ivars; struct objc_method_list **methodLists; struct objc_cache *cache; struct objc_protocol_list *protocols; };
至此,可以看到Objective-C對象係統的基石:struct objc_class結構:
isa指針:指向該對象所屬類型的類型對象(Class Object)。在Objective-C中,類也是用對象來表示的,而類的isa指針指向它的metaclass(存儲靜態成員變量和類方法)。 super_class指針:指向父類。 name:類名稱。 version:類的版本信息。 info:運行期使用的標誌位,比如0x1(CLS_CLASS)表示該類為普通class,0x2(CLS_META)表示該類為 metaclass。 instance_size:實例大小,即內存所占空間。 ivars:指向成員變量列表的指針。 methodLists:根據標誌位的不同可能指向不同,比如可能指向實例方法列表,或者指向類方法列表。 cache:因為Objective-C的消息轉發需要查找dispatch table甚至可能需要遍曆繼承體係,所以緩存最近使用的方法。 protocols:類需要遵守的協議。
[2] 動態地操作類
由上知道了類也是一種對象,那麼類對象也有一種類型,這種類型就是類的metaclass,因此類方法其實就是metaclass的成員方法,類和metaclass是配套出現的。
那麼metaclass的isa指針和super_class指針怎麼指向的呢?
如果metaclass對應基類,那麼它的isa指向自身、super_class指針指向對應的類(基類);如果不是則isa指針指向基類的metaclass、super_class指針指向父類的metaclass。
基類的isa指針為nil。
這不禁讓我又想起了Python中類似的設計思想,比如整型數字2的類型是PyIntObject,而PyIntObject類的類型是PyTypeObject,PyTypeObject的類型是PyTypeObject。最終止於此。
同樣地,Python中也有metaclass的存在。
知道了類的表示結構,我們可以動態地對類進行操作,加深理解。
// // main.m // HelloOC // // Created by Jason Lee on 12-2-17. // Copyright (c) 2012年 XXX. All rights reserved. // #import <Foundation/Foundation.h> #import <objc/objc.h> #import <objc/runtime.h> void selfIntro(idself, SEL_cmd); int main (int argc, constchar * argv[]) { @autoreleasepool { //Create class & metaclass as a pair Class demoClass = objc_allocateClassPair([NSObjectclass], "NSDemo", 0); BOOL isOk = NO; //"v@:" indicates the function type : v - void, @ - object, : - SEL //向methodLists指向添加數據 isOk = class_addMethod(demoClass, @selector(intro), (IMP)&selfIntro, "v@:"); isOk == YES ? nil : NSLog(@"failed on class_addMethod\n"); //向ivars指向添加數據 isOk = class_addIvar(demoClass,"myVar", sizeof(id), log2(sizeof(id)), "@"); isOk == YES ? nil : NSLog(@"failed on class_addIvar\n"); objc_registerClassPair(demoClass); id demo = class_createInstance(demoClass, 0); if ([demo respondsToSelector:@selector(intro)]) { [demo performSelector:@selector(intro)]; } object_setInstanceVariable(demo, "myVar", nil); void *outValue = (void *)0x1; object_getInstanceVariable(demo, "myVar", &outValue); if (nil == outValue) { NSLog(@"Hello,nil\n"); //printed } object_dispose(demo); } return0; } void selfIntro(idself, SEL_cmd) { NSLog(@"selfIntro\n"); Class isa = self->isa; //At first, isa is class NSDemo while (1) { if (isa == isa->isa) { //Finally, NSObject's metaclass points to itself NSLog(@"%p, %@", isa, objc_getMetaClass(class_getName([isa class]))); break; } NSLog(@"%p, %@", isa, objc_getMetaClass(class_getName([isa class]))); isa = isa->isa; //Then, isa is assigned to NSDemo's metaclass } }
[3] 實例化
要實例化出一個對象,需要根據類的定義來進行。類的定義包括類名稱、數據和操作數據的方法。
編譯過程,類的信息會被記錄下來,供runtime system使用,同時編譯器會為每個類創建唯一的一個對象來表示它:class object。如果從功能上說,class object也是factory object,它能夠執行類方法,負責創建實例。
從這個角度來看,我在思考class object是否就是metaclass,但是不能確認。
Apple官方文檔TOCPL中Class Objects一章有這麼一句,“a class object keeps the prototype of a class instance”,但metaclass並不能作為實例原型。
於是我認為class object是運行時class和metaclass結合起來的受限表現,能夠訪問編譯器捕捉下來的類信息,沒有成員變量,不能調用成員方法,但是可以執行類方法。
從源碼層次來看,class object是由類名來表示,比如下述代碼中:
int version = [NSString version];
NSString代表著class object。
首先,class object會被runtime system發送initialize消息進行初始化,讓其做好運行時的準備,比如初始化靜態變量。
之後,可以調用class object的方法(類方法)alloc來為新的實例對象分配內存空間,將其所有變量初始化為0,isa指針指向所屬類。
最後再調用init函數進行必要的初始化。
寫到這裏的時候,突然要變更辦公位置,思路被打斷了,就先寫到這裏。
最後,留一個在SO上麵看到的問題,我也疑惑,隻能有幾分猜測:https://stackoverflow.com/questions/8847146/whats-is-methodlists-attribute-of-the-structure-objc-class-for
[這篇文章是我對SO上的問題的解答:https://blog.csdn.net/jasonblog/article/details/7303618]
[Last Updated] 2012-03-17
Jason Lee @ 杭州
博客:https://blog.csdn.net/jasonblog
微博:https://weibo.com/jasonmblog
GitHub: https://github.com/siqin最後更新:2017-04-02 22:16:24