ios - objectC 的isa 詳解


每個Objective-C對象都有一個隱藏的數據結構,這個數據結構是Objective-C對象的第一個成員變量,它就是isa指針。

在NSObject.h里面: 

@interface NSObject <NSObject> {

    Class isa  OBJC_ISA_AVAILABILITY;

}

再點開 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

}

這一些定義對於懂的人自然懂,不會的人根本看不懂。建議看完下面的例子,再點開參考里面的鏈接仔細看一遍。

 

現在我們知道的是,對於我們新建的一個類,都會有一個隱藏的屬性isa,可以通過它進行一些訪問。

我們現在新建一個類Parent,繼承於NSObject, 里面有成員方法-(void)selectorP,類方法+(void)ClassSelectorP。

再新建一個類Child,繼承於Parent,里面有成員方法-(void)selectorC, 類方法+(void)ClassSelectorC。

現在我們新建一個實例Child* child = [Chlid new];

1,當我們調用[child class] 的時候,child就會通過isa指針去找到Child的class。

2,當我們調用[child superclass]的時候,child 通過isa找到Child的class,再通過super_class,找到Parent的class。

在這里,再普及objc_class 的兩種類型:

 class     實例對象(child、Child)的isa指向的結構體;

metaclass  class的isa指向的一個結構體;

3,接着,調用[child SelectorC],child通過isa找到Child的class,在class(注意看上面 struct objc_class 的定義)的方法列表里面找到SelectorC;

4,再試着調用[child SelectorP],child通過isa找到Child的class,發現class里面並沒有這個方法,通過class里面的super_class找到Parent的class,在里面的方法列表找到了SelectorP;

5,再是類方法[Child ClassSelectorC],Child(請注意,大寫)通過isa找到Child的class,通過class的isa找到Child的metaclass,在metaclass的方法列表里面找到了ClassSelectorC;

6,再試着調用[Child ClassSelectorP],Child通過isa找到Child的class,通過class的isa找到Child的metaclass,發現metaclass里面並沒有這個方法,通過metaclass里面的super_class找到Parent的metaclass,在里面的方法列表找到了ClassSelectorP;   

 

 

- (void)viewDidLoad {

    [super viewDidLoad];

    Class clazz = [self class];

    Class clarr = [AroundMapController class];

    Class metalclazz = objc_getMetaClass("AroundMapController");

    if (class_respondsToSelector(metalclazz, @selector(viewWillAppear:))) {

        NSLog(@"ok");

    }

    if (clarr == clazz) {

        NSLog(@"2 ok");

    }

}

這個是驗證runtime的機制,可以把這段代碼復制到自己的controller.m里面,運行一下。記得把AroundMapController改成自己的controller的名字,還有引入頭文件<objc/runtime.h>

 

 

這是幾個例子基本上已經涵蓋了大多數調用的情況。

細心的朋友可能已經發現,上面的例子中,child通過isa找到的類對象,其實就是Child 通過isa找到的class。(如果能理解這一點,基本上也算對objectC的isa機制也算入門)

 

最后為了理解class和metaclass的作用,大家可以換位思考一下,如果我們作為runtime的設計者,當開發者新建出來一個實例對象child的時候,我們應該存儲child的屬性和方法,同時又該如何響應其方法調用,最后還要記錄與Parent之間的繼承關系。

這時候,再來看看,這種圖。可以加深對isa機制的理解:

 

 

參考

http://www.cocoachina.com/ios/20141018/9960.html

http://blog.csdn.net/jasonblog/article/details/7246822

http://blog.csdn.net/totogo2010/article/details/8081253

 

 

 

--問答題---

如果給你一個child的實例對象,要如何才能訪問到它的父類的靜態方法ClassSelectorP?


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM