我們平時(shí)編寫的Object-C代碼蛇尚,底層實(shí)現(xiàn)其實(shí)都是C/C++代碼,基于C/C++結(jié)構(gòu)體實(shí)現(xiàn)的
目錄
-
1、OC對(duì)象的本質(zhì)
- 1.1. 面試題
- 1.2. Go2Shell插件(快速定位終端)
- 1.3. 使用clang將OC代碼轉(zhuǎn)為C/C++
- 1.4. 實(shí)時(shí)查看內(nèi)存數(shù)據(jù)
- 1.5. 復(fù)雜的繼承結(jié)構(gòu)分析
- 1.6. 屬性和方法
1.1、面試題
- 一個(gè)NSObject對(duì)象占用多少內(nèi)存锦担?
// 獲得NSObject類的實(shí)例對(duì)象的成員變量所占用的大小 >> 8
NSLog(@"%zd", class_getInstanceSize([NSObject class]));
// 獲得obj指針?biāo)赶騼?nèi)存大小 >>16
NSLog(@"%zd", malloc_size((__bridge const void *)obj));
2019-06-01 16:16:19.774722+0800 Interview001-OC對(duì)象的本質(zhì)[2222:353779] 8
2019-06-01 16:16:19.774927+0800 Interview001-OC對(duì)象的本質(zhì)[2222:353779] 16
結(jié)論:
- 系統(tǒng)分配了16個(gè)字節(jié)給 NSObject 對(duì)象
- 但 NSObject 對(duì)象內(nèi)部只使用了8個(gè)字節(jié)的空間诬滩,存放的是isa指針
- 對(duì)象的isa指針指向哪里?
- instance對(duì)象的isa指向class對(duì)象
- class對(duì)象的isa指向meta-class對(duì)象
- meta-class對(duì)象的isa指基類的meta-class對(duì)象
- OC的類信息存放在哪里坊饶?
- 對(duì)象方法、屬性殴蓬、成員變量匿级、協(xié)議信息,存放在class對(duì)象中
- 類方法染厅,存放在meta-class對(duì)象中
- 成員變量的具體值痘绎,存放在instance對(duì)象中
1.2、Go2Shell插件 官網(wǎng)
下載
安裝
使用
1.3肖粮、clang將OC代碼轉(zhuǎn)為C/C++
?? 首先定位到當(dāng)前文件夾下
$ clang -rewrite-objc main.m -o main.cpp
// 指定平臺(tái)和架構(gòu)
$ xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc [輸入文件] -o [輸入文件]
// 在Xcode下可使用以下命令:
$ xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main-arm64.cpp
$ xcrun -sdk iphoneos clang -arch i386 -rewrite-objc main.m -o main-i386.cpp
可參考:使用clang將OC代碼轉(zhuǎn)為C/C++ - Cotin's
轉(zhuǎn)換結(jié)果
通過將OC轉(zhuǎn)換為C/C++代碼孤页,我們從源碼中可查看NSObject的底層實(shí)現(xiàn)
@interface NSObject {
Class isa;
}
@end
=>
struct NSObject_IMPL {
Class isa;
};
// Class 是指向結(jié)構(gòu)體的指針
typedef struct objc_class *Class;
創(chuàng)建一個(gè)Student類
struct NSObject_IMPL {
Class isa;
};
struct Student_IMPL {
struct NSObject_IMPL NSObject_IVARS;
int _no;
int _age;
};
@interface Student : NSObject
{
@public
int _no;
int _age;
}
@end
@implementation Student
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
Student *student = [[Student alloc] init];
student->_no = 4;
student->_age = 5;
struct Student_IMPL *stuImpl = (__bridge struct Student_IMPL *)(student);
NSLog(@"no is %d, age is %d", stuImpl->_no, stuImpl->_age);
}
return 0;
}
2019-06-01 21:04:08.746698+0800 Interview002[2973:555547] no is 4, age is 5
20_58_22__06_01_2019.jpg
1.4、實(shí)時(shí)查看內(nèi)存數(shù)據(jù)
Debug -> Debug Workflow -> View Memory (Shift + Command + M)
1dm9tuPP22_47_07__06_02_2019.jpg
1eY6ToWS22_47_51__06_02_2019.jpg
1.5尿赚、復(fù)雜的繼承結(jié)構(gòu)分析
一個(gè)Student對(duì)象繼承于Person對(duì)象散庶,Student占用多少內(nèi)存空間蕉堰?
@interface Person : NSObject
{
int _age;
}
@end
@interface Student : Person
{
int _no;
}
@end
分析結(jié)果
struct NSObject_IMPL {
Class isa;
};
struct Person_IMPL {
struct NSObject_IMPL NSObject_IVARS;
int _age;
};
struct Student_IMPL {
struct Person_IMPL Person_IVARS;
int _no;
};
1.6、屬性和方法
@interface Person : NSObject
{
int _age;
}
@property(nonatomic, assign) int height;
@end
=>
struct Person_IMPL {
struct NSObject_IMPL NSObject_IVARS;
int _age;
int _height;
};
我們創(chuàng)建出來的實(shí)例對(duì)象悲龟,內(nèi)存中只存成員變量屋讶,不存方法,為什么不設(shè)計(jì)成把方法放到實(shí)例變量里面去须教?
Person對(duì)象可能創(chuàng)建很多個(gè)皿渗,每一個(gè)實(shí)例對(duì)象的內(nèi)存都放自己的成員變量,方法的代碼都是一樣的轻腺,只放一份就行了乐疆。