iOS Isa、Superclass、類、元 -- 對象的本質、內部原理

OC對象 主要分三種:

instance 對象(實例對象)

class 對象(類對象)

meta-class 對象 (元類對象)

1:一個實例對象 在內存中存儲的信息:isa指針、其他變量(這個是成員變量的值,比如說,self.age = 10, 10放在裏面)

2:類對象

  NSObject *objec1 = [[NSObject alloc] init];
        NSObject *objec2 = [[NSObject alloc] init];
        
        // 獲取類對象的三種方式
        Class objectClass1 = [objec1 class];
        Class objectCalss2 = [objec2 class];
        Class objectClass3 = object_getClass(objec1);
        Class objectClass4 = object_getClass(objec2);
        Class objectClass5 = [NSObject class];
        

一個類的類對象是唯一的,在內存中是一份的,所以上述objectClass1、2、3、4、5地址是一樣的

2018-07-04 20:39:35.659080+0800 new[4539:831047] 0x7fffb08b9140,0x7fffb08b9140,0x7fffb08b9140,0x7fffb08b9140,0x7fffb08b9140

類對象在內存中存儲的信息:isa指針、superclass指針、類的屬性信息(@property)、類的對象方法信息(instance method)(減號的方法)、類的協議信息(protocol)、類的成員變量信息(ivar)(這個成員變量是 成員變量的名字、還有成員變量的類型,比方說 string類型,名字叫age)

3:meta-class 元類對象

獲取元類對象

跟class和實例對象不是一種地址

 

class方法返回的就是類對象,不管你調用多少次,[[NSObject class] class]

元類對象在內存中儲存的信息:類方法。

objectMetaClass是NSObject的meta-Class對象

每個類在內存中有且只有一個metal-Class對象

meta-Class對象和class對象的內存結構是一樣的,但是用途不一樣,在內存中存儲的信息主要包括:isa指針、superclass、類方法信息。

可以判斷是否是元類對象。:

class_isMetaClass(objectMetaClass);

 

 

 

object_getClass與objc_getClass分別是什麼意思

 

 

 

A>: Class objc_getClass(const char *name)

a:傳入的是字符串類名,返回對應的類對象。

 

 

B>: Class object_getClass(id obj)

a:傳進去的obj可能是instance對象、class對象、meta-class對象

b:如果是instance對象,返回class對象

c:如果是class對象,返回的是meta-class對象

d:如果是meta-class對象,返回的是NSObject(基類)的meta-class對象。

 

C>: -(Class)class 、+(Class)class

返回的就是類對象

 

isa指針:

class對象的superclass指針:Student繼承自Person,Person繼承自NSObject。當Student實例變量去調用實例方法時的過程。

@interface Person : NSObject
{
    int _df;
}

- (void)personMethod;

@end

@implementation Person

- (void)personMethod
{   
}
@end

@interface Student : Person
{
    double _no;
}

- (void)studentMethod;

@end

@implementation Student

- (void)studentMethod
{   
}
@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        Student *stu = [[Student alloc] init];
        [stu personMethod];   
    }
    return NSApplicationMain(argc, argv);
}

這個原理過程就是下面圖中所示,stu先按照上圖所示的,stu的實例對象的isa指針,找到本身stu類(因爲類裏有對象方法,同時有superclass指針,)發現並未有該方法,根據superclass指針,找到Person的類對象,就能夠找到Person類的對象方法,正好有剛調用的personMehod方法,即可實現。

假設Student類對象調用 load方法,那麼過程就是下面圖中所示:Student類根據isa指針找到自己的meta-class對象,在元類對象中並未發現load方法,就會根據superclass找到父類的meta-class對象,也就是Person的元類對象,發現也沒有,再根據person原類對象的superclass找到父類也就是NSObject的meta-class對象,從而找到load方法。這裏需要注意,假設NSObject沒有load方法,那麼現在NSObject這個基類的meta-class的superclass會找到NSObject的class,如果再沒找到,纔會報錯。

總結一下:就是superclass找的是類方法 都是找的meta-class對象  如果找的是實例方法 ,那麼找的都是類對象。

每一個類 都有自己的元類對象

假設Person和Student都有實例test方法。【student test】調用的時候,會直接調用student的test方法。原因:面向對象的思想的話是子類重寫父類,那麼肯定會調用子類的方法。如果按照上面的本質去解釋的話:子類isa指針找到本類class對象,發現有test方法,那麼它就直接執行了,不會再找父類了。

 

如果是

 

驗證問題:

這個是NSObject分類,只實現了實例方法test。
#import "NSObject+test.h"

@implementation NSObject (test)

- (void)test
{
    NSLog(@"sfd");
}



@end
這裏是person方法,並未實現test類方法
@interface Person : NSObject

+ (void)test;

@end

@implementation Person

@end

 

 
#import "NSObject+test.h"
int main(int argc, const char * argv[]) { @autoreleasepool { 
[Person test];
 }
 return NSApplicationMain(argc, argv);
}

 

 

那麼這個能夠調用? 是否會報錯? 答案很明顯,不會

 

 

2018-07-10 20:08:51.314998+0800 new[1765:218776] sfd

原因就是上面基類的meta-class方法如果沒有找到對應的類方法的時候,它的superclass指針會指向基類的class對象,也就是NSObject類,找到了test方法,所以就調用了。對於本質objc_Send()方法而言,是沒有減號和加號的區別方法的,所以直接調用。
 

注意:

isa不是直接指向本類的對象的,從64bit開始,需要一次運算才能計算出真實的地址

但是superclass是直接指向的,並不需要轉換

 

2:對象的isa指針指向哪裏?

instance對象isa指向class對象

class對象isa指向meta-class對象

meta-class對象isa指向基類meta-class對象

 

3:OC的類信息存放在哪裏?

對象方法、屬性、成員變量、協議信息存放在class對象中

類方法存在meta-class對象中

成員變量的具體值,存放在instance對象

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章