iOS 方法調(diào)用的過程

先看一道題:

#import "RootVC.h"
@interface NSObject (myTest)
+ (void) testFunc;
@end

@implementation NSObject (myTest)
-(void) testFunc
{
    NSLog(@"testFunc: 執(zhí)行");
}
@end

@implementation RootVC

- (void)viewDidLoad
{
    [super viewDidLoad];
    [NSObject testFunc];
    NSObject *obj = [[NSObject alloc]init];
    [obj testFunc];
}
@end

程序執(zhí)行的結(jié)果是什么?為什么呢?
如果要解答這道題,就需要對(duì)OC的方法調(diào)用過程非常了解才能答對(duì)。
先看看運(yùn)行結(jié)果:

2017-08-07 15:38:14.835648+0800 testruntime[12184:1830852] testFunc: 執(zhí)行
2017-08-07 15:38:14.835712+0800 testruntime[12184:1830852] testFunc: 執(zhí)行

類在Runtime中的結(jié)構(gòu)

struct objc_class 
{
    Class isa  OBJC_ISA_AVAILABILITY;
    //isa指針,這是個(gè)啥?,表示是一個(gè)什么,
    //實(shí)例的isa指向類對(duì)象,類對(duì)象的isa指向元類
#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;
    //方法緩存列表
    //調(diào)用過的方法存入緩存列表,下次調(diào)用先找緩存

    struct objc_protocol_list *protocols                     OBJC2_UNAVAILABLE;
   //協(xié)議列表

#endif

} OBJC2_UNAVAILABLE;
/* Use `Class` instead of `struct objc_class *` */

元類MetaClass

所有的類自身也是一個(gè)對(duì)象,可以向這個(gè)對(duì)象發(fā)送消息(即調(diào)用類方法)。
NSArray *array = [NSArray array];
+array消息發(fā)送給了NSArray類,而這個(gè)NSArray也是一個(gè)對(duì)象。
既然是對(duì)象,那么它也是一個(gè)objc_object指針,包含一個(gè)指向其類的一個(gè)isa指針。為了調(diào)用+array方法,這個(gè)類的isa指針必須指向一個(gè)包含這些類方法的一個(gè)objc_class結(jié)構(gòu)體。這就需要meta_class概念。
meta_class是一個(gè)類對(duì)象的類。當(dāng)我們向一個(gè)對(duì)象發(fā)送消息時(shí),Runtime會(huì)在這個(gè)對(duì)象所屬的這個(gè)類的方法列表中查找方法。而向一個(gè)類發(fā)送消息時(shí),會(huì)在這個(gè)類的meta_class的方法列表中查找。meta_class很重要,因?yàn)樗鎯?chǔ)著一個(gè)類的所有的類方法。每個(gè)類都會(huì)有一個(gè)單獨(dú)的meta_class,因?yàn)槊總€(gè)類的類方法基本不可能完全相同。

方法調(diào)用的過程

調(diào)用方法分為調(diào)用實(shí)例方法和調(diào)用類方法,在結(jié)構(gòu)體我們可以看到第一個(gè)就是一個(gè) isa 指針,會(huì)指向類對(duì)象或者元類。

每個(gè)實(shí)例對(duì)象有個(gè)isa的指針,指向?qū)ο蟮念悾?br> 類里也有個(gè)isa的指針, 指向meteClass(元類)。
元類保存了類方法的列表。當(dāng)類方法被調(diào)用時(shí),先會(huì)從元類本身查找類方法的實(shí)現(xiàn),如果沒有,元類會(huì)向他父類查找該方法。同時(shí)注意的是:元類(meteClass)也是類,它也是對(duì)象。元類也有isa指針,它的isa指針最終指向的是一個(gè)根元類(root meteClass)。根元類的isa指針指向本身,這樣形成了一個(gè)封閉的內(nèi)循環(huán)。

方法調(diào)用的過程
1.在對(duì)象自己緩存的方法列表中去找要調(diào)用的方法,找到了就直接執(zhí)行其實(shí)現(xiàn)。
2.緩存里沒找到,就去上面說的它的方法列表里找,找到了就執(zhí)行其實(shí)現(xiàn)。
3.還沒找到,說明這個(gè)類自己沒有了,就會(huì)去向其父類里執(zhí)行1、2。
4.如果找到了根類還沒找到,那么就是沒有了,會(huì)轉(zhuǎn)向一個(gè)攔截調(diào)用的方法,我們可以自己在攔截調(diào)用方法里面做一些處理。
5.如果沒有在攔截調(diào)用里做處理,那么就會(huì)報(bào)錯(cuò)崩潰。
方法調(diào)用過程.png

以上就是方法調(diào)用的過程。我們可以看到的是,所謂重寫父類方法,并不是抹除了父類方法,父類的方法還是存在的,只是我們?cè)谧宇惱锩嬲业搅司筒粫?huì)再去父類里找了,是這個(gè)層面的“覆蓋”。而我們熟悉的 super 調(diào)用父類的方法實(shí)現(xiàn),就是告知要去調(diào)用父類實(shí)現(xiàn)的標(biāo)識(shí)。

這樣回到開頭的題目,答案自然一目了然啊。
類方法去metaclass里面找,沒找到,去superclass也就是NSObject去找,找到了方法就去執(zhí)行。
實(shí)例方法直接找到就進(jìn)行執(zhí)行。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 2,032評(píng)論 0 9
  • 首先說明,這篇文章幾乎都是抄錄的別人的博客,簡(jiǎn)書文章,在此總結(jié),只是為了方便記憶和以后閱讀,如果有什么失禮的地方,...
    LiYaoPeng閱讀 5,329評(píng)論 1 14
  • 這篇文章完全是基于南峰子老師博客的轉(zhuǎn)載 這篇文章完全是基于南峰子老師博客的轉(zhuǎn)載 這篇文章完全是基于南峰子老師博客的...
    西木閱讀 30,874評(píng)論 33 466
  • Objective-C語(yǔ)言是一門動(dòng)態(tài)語(yǔ)言,它將很多靜態(tài)語(yǔ)言在編譯和鏈接時(shí)期做的事放到了運(yùn)行時(shí)來處理。這種動(dòng)態(tài)語(yǔ)言的...
    有一種再見叫青春閱讀 669評(píng)論 0 3
  • 耳旁播放著竹林流水小鳥叫聲的音樂,當(dāng)你靜靜躺在瑜伽墊上,你忘記了周遭的一切事物,努力忘記現(xiàn)實(shí)中所有煩惱,你的腹部隨...
    294cfe96d700閱讀 1,227評(píng)論 0 2

友情鏈接更多精彩內(nèi)容