执行如下指令,生成
.cpp
文件
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main-arm64.cpp
检索Student_IMPL {
查看Student结构体实现如下:
struct Student_IMPL {
struct NSObject_IMPL NSObject_IVARS;
int _no;
int _age;
};
struct NSObject_IMPL NSObject_IVARS
是NSObject
的底层实现,即NSObject_IMPL
:
struct NSObject_IMPL {
Class isa
};
所以继承自NSObject
的Student
的实现相当于:
struct Student_IMPL {
Class isa;
int _no;
int _age;
};
如上所示,一个子类
会将自父类
继承来的成员变量
放在成员变量列表
的起始位置,先排列父类的成员变量
,然后再排列自己的成员变量
.
Student对象的内存分配如下:
image.pngimage.pngobj指针的地址为:Student对象的第一个成员变量的地址:isa的地址.
image.png
通过上面两幅图可以证明:Student底层本质就是Student_IMPL结构体.
Student对象 结构图:
image.png思考:
image.png内存对其:
- 结构体内存大小 必须为 该结构体最大成员变量占用内存的整数倍.Person结构体的最大内存成员变量为
Struct NSObject_IMPL Person_IVARS
8个字节.所以为16个字节.
image.png
代码打印:
image.png为什么Person对象分配的内存和实际占用的内存都为16?
Person 底层实现:
struct NSObject_IMPL {
Class isa;
}
struct Person_IMPL {
struct NSObject_IMPL NSObject_IVARS;
int _no;
}
@interface Person : NSObject
{
int _no;
}
image.png
Person对象正常应该占用12个字节.因为内存对其原则:
结构体大小 需为 结构体最大成员变量(struct NSObject_IMPL)所占内存的整数倍
所以Person的占用的内存大小为 8 * 2 = 16.从如下函数中也可看出
class_getInstanceSize
底层调用的是如下函数:
uint32_t alignedInstanceStart() {
return word_align(unalignedInstanceStart());
}
unalignedInstanceStart()
该函数为未做内存对其的内存大小//12
word_align(12)
该函数对其后的内存大小//16
instance对象中只有 成员变量,没有方法列表.方法列表在Class对象当中.
@interface Person : NSObject
{
int _no;
}
@property (nonatomic,assign) int height;
@end
Person instance对象的底层实现:
struct Person_IMPL {
struct NSObject_IMPL NSObject_IVARS;
int _no;
int _height;
};
可以看到实现中没有height
的getter
和setter
方法.
设计技巧:
- Person 类的不同
instance
对象的成员变量(_no,_height)
的值会不同.所以在不同instance
对象的实现中记录不同instance
的成员变量的值. - 但是Person 实例的方法都是相同的,只需要一份就够了,所以方法列表不在
instance
对象中,而在Class
对象的方法列表中,Class
对象 在内存中只存在一份.