NSObject
先來(lái)看一段OC代碼:
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSObject *objc = [[NSObject alloc] init];
}
return 0;
}
通過(guò)以下終端命令:(指定 arm64
架構(gòu)模式)
$ xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main-arm64.cpp
在 main-arm64.cpp
該文件中纽疟,可以找到以下代碼:
struct NSObject_IMPL {
Class isa;
};
通過(guò) command
+ 點(diǎn)擊
進(jìn)入 NSObject
查看如下:
@interface NSObject <NSObject> {
Class isa;
}
不難看出,NSObject_IMPL
就是通過(guò) C
語(yǔ)言轉(zhuǎn)換后的結(jié)構(gòu)體
該結(jié)構(gòu)體 NSObject_IMPL
中只有一個(gè) isa
指針變量:
在 64bit
中是 8個(gè)字節(jié)
芜赌;在 32bit
中是 4個(gè)字節(jié)
下面的代碼仰挣,在內(nèi)存中都干了些什么?
NSObject *objc = [[NSObject alloc] init];
答:系統(tǒng)為 NSObject
對(duì)象分配了 8個(gè)字節(jié)
的內(nèi)存缠沈,用來(lái)存放 isa
指針膘壶。
也就是說(shuō):
objc
存儲(chǔ)的就是 isa
的地址;
objc
只想內(nèi)存中 NSObject
對(duì)象地址洲愤,即指向內(nèi)存中的結(jié)構(gòu)體颓芭,也就是 isa
的位置。
自定義類(lèi)
看下面代碼:
#import <Foundation/Foundation.h>
@interface Student : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) int age;
@end
@implementation Student
int main(int argc, const char * argv[]) {
@autoreleasepool {
Student *stu = [[Student alloc] init];
stu.name = @"張三";
stu.age = 5;
NSLog(@"%@", stu);
}
return 0;
}
@end
通過(guò)終端生成 .cpp
文件并查看:
struct Student_IMPL {
struct NSObject_IMPL NSObject_IVARS;
int _age;
NSString *_name;
};
第一個(gè)是不是很眼熟柬赐?是我們上面剛提到的 NSObject_IMPL
的實(shí)現(xiàn)亡问,并且我們知道其內(nèi)部就是 Class isa
。因此我們?nèi)藶榈母囊幌?Student_IMPL
:
struct Student_IMPL {
Class *isa;
int _age;
NSString *_name;
};
繼承關(guān)系
我們用 Student
、 Person
州藕、NSObject
來(lái)說(shuō)明束世,它們?nèi)咧g的繼承關(guān)系如下:
Student --繼承自--> Person --繼承自--> NSObject
NSObject_IMPL
:
struct NSObject_IMPL {
Class isa;
};
Person_IMPL
:
struct Person_IMPL {
struct NSObject_IMPL NSObject_IVARS;
};
Student_IMPL
:
struct Student_IMPL {
struct Person_IMPL NSObject_IVARS;
};
結(jié)論:只要是繼承自 NSObject
的對(duì)象,底層結(jié)構(gòu)體內(nèi)一定有一個(gè) isa
指針
OC對(duì)象的種類(lèi)
種類(lèi) | 說(shuō)明 | 存儲(chǔ)內(nèi)容 |
---|---|---|
instance對(duì)象 (實(shí)例對(duì)象) |
通過(guò)類(lèi)alloc出來(lái)的對(duì)象床玻,每次調(diào)用alloc都會(huì)產(chǎn)生新的instance對(duì)象 | 1. isa指針 2. 成員變量的值 |
class對(duì)象 (類(lèi)對(duì)象) |
通過(guò)class方法或runtime方法得到一個(gè)class對(duì)象 | 1. isa指針 2. superclass指針 3. 類(lèi)的屬性信息(@property)毁涉,類(lèi)的成員變量信息(ivar) 4. 類(lèi)的對(duì)象方法信息(instance method),類(lèi)的協(xié)議信息(protocol) |
meta-class對(duì)象 (元類(lèi)對(duì)象) |
runtime中 object_getClass 傳入類(lèi)對(duì)象 |
1. isa指針 2. superclass指針 3. 類(lèi)的類(lèi)方法的信息(class method) |
說(shuō)明:
- 每個(gè)類(lèi)在內(nèi)存中有且只有一個(gè)
class對(duì)象
(打印內(nèi)存地址可證明) - 每個(gè)類(lèi)在內(nèi)存中有且只有一個(gè)meta-class對(duì)象锈死。
對(duì)象的isa指針
- 對(duì)象調(diào)用實(shí)例方法贫堰,如下:
[stu stundentMethod];
說(shuō)明:
instance 的 isa
指向 class 。
此時(shí)待牵,isa
找到 class其屏,最后找到對(duì)象方法的實(shí)現(xiàn)進(jìn)行調(diào)用。
- 當(dāng)類(lèi)對(duì)象調(diào)用類(lèi)方法缨该,如下:
[Student studentClassMethod];
說(shuō)明:
class 的 isa
指向 meta-class偎行。
此時(shí),isa
找到 meta-class压彭,最后找到類(lèi)方法的實(shí)現(xiàn)進(jìn)行調(diào)用睦优。
- 當(dāng)對(duì)象調(diào)用其父類(lèi)對(duì)象方法,如下:
[stu personMethod];
說(shuō)明:
(1) instance 的 isa
找到 Student
類(lèi)
(2) 通過(guò) Student
類(lèi)中的 superclass
指針找到 Person
類(lèi)壮不,找到對(duì)象方法的實(shí)現(xiàn)進(jìn)行調(diào)用
(3) 若沒(méi)找到,通過(guò) Person
類(lèi)的 superclass
指針找到 NSObject
類(lèi)皱碘,去尋找響應(yīng)的方法
- 當(dāng)類(lèi)對(duì)象調(diào)用父類(lèi)的類(lèi)方法询一,如下:
[Student personClassMethod];
說(shuō)明:
(1) instance 的 isa
找到 Student
類(lèi)
(2) 通過(guò) Student
類(lèi)中的 superclass
指針找到 Person
的 meta-class,最后找到類(lèi)方法的實(shí)現(xiàn)進(jìn)行調(diào)用
總結(jié):
1. instance的isa指向class
2. class的isa指向meta-class
3. meta-class的isa指向基類(lèi)的meta-class癌椿,基類(lèi)的isa指向自己
4. class的superclass指向父類(lèi)的class健蕊,如果沒(méi)有父類(lèi),superclass指針為nil
5. meta-class的superclass指向父類(lèi)的meta-class踢俄,基類(lèi)的meta-class的superclass指向基類(lèi)的class
6. instance調(diào)用對(duì)象方法的軌跡缩功,isa找到class,方法不存在都办,就通過(guò)superclass找父類(lèi)
7. class調(diào)用類(lèi)方法的軌跡嫡锌,isa找meta-class,方法不存在琳钉,就通過(guò)superclass找父類(lèi)