深入理解Objective-C中實(shí)例、類對象、元類對象之間的關(guān)系

實(shí)例、類對象、元類對象之間的關(guān)系可以用下面這張經(jīng)典的圖來展示:

class-diagram.jpg

總結(jié):

  • 實(shí)例的isa指向類對象
  • 類對象的isa指向元類對象
  • 元類對象的isa指針指向根元類對象
  • 根元類的父類是根類對象

根元類的父類是根類對象意味著什么呢?

我們知道如果調(diào)用類方法,會沿著元類對象的繼承鏈依次向上查找方法的實(shí)現(xiàn)。

因?yàn)楦惖母割愂歉悓ο?,所以如果在跟元類中無法查找到該方法的實(shí)現(xiàn),會到根類對象中去查找。

而根類對象中的方法都是實(shí)例方法。

所以這意味著,如果一個(gè)類的類方法沒有被實(shí)現(xiàn),就會去調(diào)用它的根類(NSObject)中的同名實(shí)例方法。

我們用代碼驗(yàn)證一下。

NSObject新建一個(gè)Category,并添加一個(gè)名為foo的實(shí)例方法。方法的實(shí)現(xiàn)只是簡單打印foo字符串

//NSObject+Foo.h

#import <Foundation/Foundation.h>
@interface NSObject (Foo)
- (void)foo;
@end


//NSObject+Foo.m

#import "NSObject+Foo.h"
@implementation NSObject (Foo)
- (void)foo {
    NSLog(@"foo foo");
}
@end

新建一個(gè)UIView的子類,并在這個(gè)子類的.h文件中聲明一個(gè)名為foo類方法,但在.m文件中并不實(shí)現(xiàn)它。

// CView.h

#import <UIKit/UIKit.h>
@interface CView : UIView
+ (void)foo;
@end

// CView.m
#import "CView.h"
@implementation CView

@end

然后調(diào)用這個(gè)類方法[CView foo];

按理說我們沒有實(shí)現(xiàn)+ (void)foo;程序應(yīng)該崩潰。但是,實(shí)際上會調(diào)用NSObject的Category中的實(shí)例方法- (void)foo,打印出"foo foo",非常神奇

使用super關(guān)鍵字調(diào)用方法的時(shí)候,發(fā)生了什么

如果上面提到的CView有這樣一個(gè)初始化方法:

#import "CView.h"

@implementation CView
- (instancetype)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        NSLog(@"%@",NSStringFromClass([self class]));
        NSLog(@"%@",NSStringFromClass([super class]));
    }
    return self;
}
@end

問:如果調(diào)用這個(gè)初始化方法,打印的結(jié)果是什么?

要解答這個(gè)問題,我們需要了解消息傳遞的過程?

我們知道,在OC中方法調(diào)用[obj method]會被編譯器編譯為objc_msgSend,它的定義為objc_msgSend(id _Nullable self, SEL _Nonnull op, ...)

前兩個(gè)參數(shù)是固定的,分別是消息的接受者和方法選擇器。

那么super關(guān)鍵字調(diào)用方法會被轉(zhuǎn)換為objc_msgSendSuper(struct objc_super * _Nonnull super, SEL _Nonnull op, ...),第一個(gè)參數(shù)為objc_super指針

objc_super是下面的數(shù)據(jù)結(jié)構(gòu):

/// Specifies the superclass of an instance. 
struct objc_super {
    /// Specifies an instance of a class.
    __unsafe_unretained _Nonnull id receiver;

    /// Specifies the particular superclass of the instance to message. 
#if !defined(__cplusplus)  &&  !__OBJC2__
    /* For compatibility with old objc-runtime.h header */
    __unsafe_unretained _Nonnull Class class;
#else
    __unsafe_unretained _Nonnull Class super_class;
#endif
    /* super_class is the first class to search */
}

其中的receiver是類的一個(gè)實(shí)例,也就是self。

也就是說,最終消息的接受者還是self這個(gè)實(shí)例。只不過,objc_msgSendSuper查找方法實(shí)現(xiàn)的過程,是從self的父類對象開始的。

但是class方法是在根類NSObject中定義的,所以不論是[self class]還是[super class]都會調(diào)用NSObject中的實(shí)現(xiàn),而且消息的接收者也是一樣的,都是self這個(gè)實(shí)例。所以打印結(jié)構(gòu)也是一樣的,都打印self的類名。

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

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

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