深入理解iOS開發(fā)中的isa指針

深入代碼理解instance拖云、class object领猾、metaclass

面向?qū)ο缶幊讨校钪匾母拍罹褪穷惷看希旅嫖覀兙蛷拇a入手泣矛,看看OC是如何實(shí)現(xiàn)類的疲眷。

instance對象實(shí)例

我們經(jīng)常使用id來聲明一個對象,那id的本質(zhì)又是什么呢您朽?打開#import<objc/objc.h>文件狂丝,可以發(fā)現(xiàn)以下幾行代碼

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

/// 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;

通過注釋和代碼不難發(fā)現(xiàn),我們創(chuàng)建的一個對象或?qū)嵗鋵?shí)就是一個struct objc_object結(jié)構(gòu)體哗总,而我們常用的id也就是這個結(jié)構(gòu)體的指針几颜。

這個結(jié)構(gòu)體只有一個成員變量,這是一個Class類型的變量isa讯屈,也是一個結(jié)構(gòu)體指針菠剩,那這個指針又指向什么呢?

面向?qū)ο笾忻恳粋€對象都必須依賴一個類來創(chuàng)建耻煤,因此對象的isa指針就指向?qū)ο笏鶎俚念惛鶕?jù)這個類模板能夠創(chuàng)建出實(shí)例變量、實(shí)例方法等准颓。
比如有如下代碼

NSString *str = @"Hello World";

通過上文我們知道這個str對象本質(zhì)就是一個objc_object結(jié)構(gòu)體哈蝇,而這個結(jié)構(gòu)體的成員變量isa指針則表明了str is a NSString,因此這個isa就指向了NSString類攘已,這個NSString類其實(shí)是類對象炮赦,不明白就繼續(xù)往下看。

class object(類對象)/metaclass(元類)

繼續(xù)查看結(jié)構(gòu)體objc_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;
    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;
/* Use `Class` instead of `struct objc_class *` */

struct objc_classs結(jié)構(gòu)體里存放的數(shù)據(jù)稱為元數(shù)據(jù)(metadata)样勃,通過成員變量的名稱我們可以猜測里面存放有指向父類的指針吠勘、類的名字、版本峡眶、實(shí)例大小剧防、實(shí)例變量列表、方法列表辫樱、緩存峭拘、遵守的協(xié)議列表等,這些信息就足夠創(chuàng)建一個實(shí)例了,該結(jié)構(gòu)體的第一個成員變量也是isa指針鸡挠,這就說明了Class本身其實(shí)也是一個對象辉饱,我們稱之為類對象類對象在編譯期產(chǎn)生用于創(chuàng)建實(shí)例對象拣展,是單例彭沼,因此前文中的栗子其實(shí)應(yīng)該表達(dá)為str的isa指針指向了NSString類對象那么這個結(jié)構(gòu)體的isa指針又指向什么呢?

類對象中的元數(shù)據(jù)存儲的都是如何創(chuàng)建一個實(shí)例的相關(guān)信息备埃,那么類對象類方法應(yīng)該從哪里創(chuàng)建呢姓惑?就是從isa指針指向的結(jié)構(gòu)體創(chuàng)建,類對象isa指針指向的我們稱之為元類(metaclass)瓜喇,元類中保存了創(chuàng)建類對象以及類方法所需的所有信息挺益,因此整個結(jié)構(gòu)應(yīng)該如下圖所示:

isa指針結(jié)構(gòu)圖

通過上圖我們可以清晰的看出來一個實(shí)例對象也就是struct objc_object結(jié)構(gòu)體它的isa指針指向類對象類對象isa指針指向了元類乘寒,super_class指針指向了父類的類對象望众,而元類super_class指針指向了父類的元類,那元類isa指針又指向了什么伞辛?為了更清晰的表達(dá)直接使用一個大神畫的圖烂翰。

實(shí)例/類對象的isa指針結(jié)構(gòu)圖

通過上圖我們可以看出整個體系構(gòu)成了一個自閉環(huán),如果是從NSObject中繼承而來的上圖中的Root class就是NSObject蚤氏。至此甘耿,整個實(shí)例類對象竿滨、元類的概念也就講清了佳恬,接下來我們在代碼中看看這些概念該怎么應(yīng)用。

類對象

有如下代碼

@interface Person : NSObject

@property (nonatomic, copy) NSString* name;
@property (nonatomic, assign) NSUInteger age;

@end

@implementation Person

@synthesize name = _name;
@synthesize age = _age;

@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Person *p = [[Person alloc] init];
        Class c1 = [p class];
        Class c2 = [Person class];
        //輸出 1
        NSLog(@"%d", c1 == c2);
    }
    return 0;
}

c1是通過一個實(shí)例對象獲取的Class于游,實(shí)例對象可以獲取到其類對象毁葱,類名作為消息的接受者時代表的是類對象,因此類對象獲取Class得到的是其本身贰剥,同時也印證了類對象是一個單例的想法倾剿。
那么如果我們想獲取isa指針的指向?qū)ο竽兀?/p>

介紹兩個函數(shù)

OBJC_EXPORT BOOL class_isMetaClass(Class cls) 
    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);

OBJC_EXPORT Class object_getClass(id obj) 
    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);

class_isMetaClass用于判斷Class對象是否為元類object_getClass用于獲取對象的isa指針指向的對象蚌成。

再看如下代碼:

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Person *p = [[Person alloc] init];
        //輸出1
        NSLog(@"%d", [p class] == object_getClass(p));
        //輸出0
        NSLog(@"%d", class_isMetaClass(object_getClass(p)));
        //輸出1
        NSLog(@"%d", class_isMetaClass(object_getClass([Person class])));
        //輸出0
        NSLog(@"%d", object_getClass(p) == object_getClass([Person class]));
    }
    return 0;
}

通過代碼可以看出前痘,一個實(shí)例對象通過class方法獲取的Class就是它的isa指針指向的類對象,而類對象不是元類担忧,類對象isa指針指向的對象是元類芹缔。

聲明:原文轉(zhuǎn)載自http://blog.csdn.net/u014205968的博文,經(jīng)過自己的修改加工僅作為記錄學(xué)習(xí)使用瓶盛。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末乖菱,一起剝皮案震驚了整個濱河市坡锡,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌窒所,老刑警劉巖鹉勒,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異吵取,居然都是意外死亡禽额,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進(jìn)店門皮官,熙熙樓的掌柜王于貴愁眉苦臉地迎上來脯倒,“玉大人,你說我怎么就攤上這事捺氢≡宥” “怎么了?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵摄乒,是天一觀的道長悠反。 經(jīng)常有香客問我,道長馍佑,這世上最難降的妖魔是什么斋否? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮拭荤,結(jié)果婚禮上茵臭,老公的妹妹穿的比我還像新娘。我一直安慰自己舅世,他們只是感情好旦委,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著雏亚,像睡著了一般缨硝。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上评凝,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天,我揣著相機(jī)與錄音腺律,去河邊找鬼奕短。 笑死,一個胖子當(dāng)著我的面吹牛匀钧,可吹牛的內(nèi)容都是我干的翎碑。 我是一名探鬼主播,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼之斯,長吁一口氣:“原來是場噩夢啊……” “哼日杈!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤莉擒,失蹤者是張志新(化名)和其女友劉穎酿炸,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體涨冀,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡填硕,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了鹿鳖。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片扁眯。...
    茶點(diǎn)故事閱讀 40,137評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖翅帜,靈堂內(nèi)的尸體忽然破棺而出姻檀,到底是詐尸還是另有隱情,我是刑警寧澤涝滴,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布绣版,位于F島的核電站,受9級特大地震影響狭莱,放射性物質(zhì)發(fā)生泄漏僵娃。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一腋妙、第九天 我趴在偏房一處隱蔽的房頂上張望默怨。 院中可真熱鬧,春花似錦骤素、人聲如沸匙睹。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽痕檬。三九已至,卻和暖如春送浊,著一層夾襖步出監(jiān)牢的瞬間梦谜,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工袭景, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留唁桩,地道東北人。 一個月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓耸棒,卻偏偏與公主長得像荒澡,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子与殃,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,086評論 2 355

推薦閱讀更多精彩內(nèi)容