日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

刨根问底Objective-C Runtime(2)- Object Class Meta Class

發布時間:2024/9/5 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 刨根问底Objective-C Runtime(2)- Object Class Meta Class 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
刨根問底Objective-C Runtime(2)- Object & Class & Meta Class

Chun Tips

專注iOS開發

刨根問底Objective-C Runtime(2)- Object & Class & Meta Class

上一篇筆記講述了objc runtime中Self 和 Super的細節,本篇筆記主要是講述objc runtime中關于Object & Class & Meta Class的細節。

習題內容

下面代碼的運行結果是?

@interface Sark : NSObject @end@implementation Sark @endint main(int argc, const char * argv[]) {@autoreleasepool {BOOL res1 = [(id)[NSObject class] isKindOfClass:[NSObject class]];BOOL res2 = [(id)[NSObject class] isMemberOfClass:[NSObject class]];BOOL res3 = [(id)[Sark class] isKindOfClass:[Sark class]];BOOL res4 = [(id)[Sark class] isMemberOfClass:[Sark class]];NSLog(@"%d %d %d %d", res1, res2, res3, res4);}return 0; }

運行結果為:

2014-11-05 14:45:08.474 Test[9412:721945] 1 0 0 0

這里先看幾個概念

什么是 id

id?在 objc.h 中定義如下:

/// A pointer to an instance of a class. typedef struct objc_object *id;

就像注釋中所說的這樣 id 是指向一個?objc_object?結構體的指針。

id 這個struct的定義本身就帶了一個 *, 所以我們在使用其他NSObject類型的實例時需要在前面加上 *, 而使用 id 時卻不用。

那么objc_object又是什么呢

objc_object?在 objc.h 中定義如下:

/// Represents an instance of a class. struct objc_object {Class isa; };

這個時候我們知道Objective-C中的object在最后會被轉換成C的結構體,而在這個struct中有一個?isa?指針,指向它的類別 Class。

那么什么是Class呢

在 objc.h 中定義如下:

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

我們可以看到 Class本身指向的也是一個C的struct?objc_class。

繼續看在runtime.h中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;

該結構體中,isa?指向所屬Class,?super_class指向父類別。

繼續看

下載objc源代碼,在?objc-runtime-new.h?中,我們發現?objc_class有如下定義:

struct objc_class : objc_object {// Class ISA;Class superclass; ...... }

豁然開朗,我們看到在Objective-C的設計哲學中,一切都是對象。Class在設計中本身也是一個對象。而這個Class對象的對應的類,我們叫它?Meta Class。即Class結構體中的?isa?指向的就是它的?Meta Class。

Meta Class

根據上面的描述,我們可以把Meta Class理解為?一個Class對象的Class。簡單的說:

  • 當我們發送一個消息給一個NSObject對象時,這條消息會在對象的類的方法列表里查找
  • 當我們發送一個消息給一個類時,這條消息會在類的Meta Class的方法列表里查找

而 Meta Class本身也是一個Class,它跟其他Class一樣也有自己的?isa?和?super_class?指針。看下圖:

  • 每個Class都有一個isa指針指向一個唯一的Meta Class
  • 每一個Meta Class的isa指針都指向最上層的Meta Class(圖中的NSObject的Meta Class)
  • 最上層的Meta Class的isa指針指向自己,形成一個回路
  • 每一個Meta Class的super class指針指向它原本Class的 Super Class的Meta Class。但是最上層的Meta Class的 Super Class指向NSObject Class本身
  • 最上層的NSObject Class的super class指向 nil

解惑

為了更加清楚的知道整個函數調用過程,我們使用clang -rewrite-objc main.m重寫,可獲得如下代碼:

BOOL res1 = ((BOOL (*)(id, SEL, Class))(void *)objc_msgSend)((id)((Class (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("class")), sel_registerName("isKindOfClass:"), ((Class (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("class")));BOOL res2 = ((BOOL (*)(id, SEL, Class))(void *)objc_msgSend)((id)((Class (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("class")), sel_registerName("isMemberOfClass:"), ((Class (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("class")));BOOL res3 = ((BOOL (*)(id, SEL, Class))(void *)objc_msgSend)((id)((Class (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Sark"), sel_registerName("class")), sel_registerName("isMemberOfClass:"), ((Class (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("class")));BOOL res4 = ((BOOL (*)(id, SEL, Class))(void *)objc_msgSend)((id)((Class (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Sark"), sel_registerName("class")), sel_registerName("isMemberOfClass:"), ((Class (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("class")));
先看前兩個調用:
  • 最外層是?objc_msgSend函數,轉發消息。
  • 函數第一個參數是?(id)((Class (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("class"))
  • 函數第二個參數是轉發的selector
  • 函數第三個參數是?((Class (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("class"))

我們注意到第一個參數和第三個參數對應重寫的是[NSObject class],即使用objc_msgSend向 NSObject Class 發送 @selector(class) 這個消息

打開objc源代碼,在?Object.mm?中發現+ (Class)class實現如下:

+ (Class)class {return self; }

所以即返回Class類的對象本身。看如下輸出:

NSLog(@"%p", [NSObject class]); NSLog(@"%p", [NSObject class]);2014-11-05 18:48:30.939 Test[11682:865988] 0x7fff768d40f0 2014-11-05 18:48:30.940 Test[11682:865988] 0x7fff768d40f0

繼續打開objc源代碼,在?Object.mm?中,我們發現?isKindOfClass的實現如下:

- (BOOL)isKindOf:aClass {Class cls;for (cls = isa; cls; cls = cls->superclass) if (cls == (Class)aClass)return YES;return NO; }

對著上面Meta Class的圖和實現,我們可以看出

  • 當 NSObject Class對象第一次進行比較時,得到它的isa為 NSObject的Meta Class, 這個時候 NSObject Meta Class 和 NSObject Class不相等。

  (這里應為是類函數的調用所以isa是元類, 如果是實例對象isa就不是元類而是類對象)

  • 然后取NSObject 的Meta Class 的Super class,這個時候又變成了 NSObject Class, 所以返回相等

所以上述第一個輸出結果是?YES?。

我們在看下 ‘isMemberOfClass’的實現:

- (BOOL)isMemberOf:aClass {return isa == (Class)aClass; }

綜上所述,當前的 isa 指向 NSObject 的 Meta Class, 所以和 NSObject Class不相等。

所以上述第二個輸出結果為?NO?。

繼續看后面兩個調用:
  • Sark Class 的isa指向的是 Sark的Meta Class,和Sark Class不相等
  • Sark Meta Class的super class 指向的是 NSObject Meta Class, 和 Sark Class不相等
  • NSObject Meta Class的 super class 指向 NSObject Class,和 Sark Class 不相等
  • NSObject Class 的super class 指向 nil, 和 Sark Class不相等

所以后面兩個調用的結果都輸出為?NO?。

下一篇博客的主要分享的內容是關于 Objective C Runtime中 消息和Category 的學習筆記。


  • 本文是關于Objective C Runtime的學習筆記。有不對的地方,歡迎大家指正。
  • 感謝@唐巧_boy和@sunnyxx分享題目。
  • 本文由@Chun發表于Chun Tips?.
  • 版權聲明:自由轉載-非商用-非衍生-保持署名 |?Creative Commons BY-NC-ND 3.0

?

Chun Tips正在使用多說

Copyright ? 2015 - Chun Ye -?Powered by?Octopress

posted on 2015-06-26 16:29 城之內 閱讀(...) 評論(...) 編輯 收藏

轉載于:https://www.cnblogs.com/HypeCheng/p/4602603.html

總結

以上是生活随笔為你收集整理的刨根问底Objective-C Runtime(2)- Object Class Meta Class的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。