一. OC的本质
- 我们平时编写的Objective-C代码,底层实现其实都是C\C++代码;
![](https://img.haomeiwen.com/i2058854/512937e42f5723c8.png)
-
Objective-C的对象、类主要是基于C\C++的
结构体
实现的
【因为只有结构体才能容纳不同的东西(比如字段、方法)】 -
将Objective-C代码转换为C\C++代码
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc OC源文件 -o 输出的CPP文件
如果需要链接其他框架,使用-framework参数。比如-framework UIKit
1.NSObject的底层实现
- OC对象本质是一个结构体;这个结构体里面有一个名叫isa的结构体指针。
-
isa指针的地址就是这个oc对象的地址。
OC对象的本质
一个NSObject对象占用多少内存?
- 系统分配了
16个字节给NSObject对象
(通过malloc_size函数获得) - 但NSObject对象内部
只使用了8个字节的空间
(64bit环境下,可以通过class_getInstanceSize函数获得)(这8个字节分配给isa指针)
2.NSObject对象的本质
NSObject里面存放了isa指针和成员变量;
没有存放方法;
![](https://img.haomeiwen.com/i2058854/19e8d844d530c15b.png)
![](https://img.haomeiwen.com/i2058854/8a57cd4e8ed21ee9.png)
- student对象的大小占用16个字节:8个字节(父类的大小:isa指针大小)+4个字节*2(两个int类型,每个int类型占用4个字节)。
- 一个对象占用的大小 = 父类的大小+子类里面字段的大小。
占用的最小是16个字节,如果不够16,系统会自动补齐为16个字节
为了内存对齐。结构体的大小,占用的字节必须是最大成员(8个字节)的倍数。配合iOS操作系统,分配的内存空间是16的倍数
思考:创建一个Person:NSObeject,Student:Person。一个Person对象、一个Student对象占用多少内存空间?
![](https://img.haomeiwen.com/i2058854/f0bf866a43749f6c.png)
![](https://img.haomeiwen.com/i2058854/1c5612777f7b519a.png)
- 一个NSObject分配了16个字节,使用了8个字节;
- Person对象大小为NSobect使用字节的大小8 + _age大小 4 = 12,为了对齐,所以结构体占用了16个字节;
- Student对象大小为Person使用的大小12个字节+_no大小4 = 16个字节,刚好是16的倍数,所以不进行补齐。所以Student占用了16个字节。
思考:创建一个Person:NSObeject,里面创建三个int类型的成员变量。一个Persont对象占用多少内存空间?
![](https://img.haomeiwen.com/i2058854/7fe487b4a6d2d8d4.png)
![](https://img.haomeiwen.com/i2058854/8f1119038683479a.png)
- 8个字节+ 4个字节 * 3 = 20 个字节。为了结构体对齐,需要是8的倍数。所以是占用了24个字节;
2.但是为了操作系统的对齐,分配的空间需要是16的倍数,所以是32个字节。
- 创建一个实例对象,至少需要多少内存?(结构体至少需要的内存,8的倍数;占用的字节)
-#import <objc/runtime.h>
class_getInstanceSize([NSObject class]);
- 创建一个实例对象,实际上分配了多少内存?(分配的空间,16的倍数)
-#import <malloc/malloc.h>
malloc_size((__bridge const void *)obj);
二.OC对象的分类
- Objective-C中的对象,简称OC对象,主要可以分为3种
1.instance对象(实例对象)
2.class对象(类对象)
3.meta-class对象(元类对象)
1. instance对象(实例对象)
instance对象就是通过类alloc出来的对象,每次调用alloc都会产生新的instance对象
instance对象在内存中存储的信息包括:
1.isa指针
2.其他成员变量
![](https://img.haomeiwen.com/i2058854/2f0ac5ebcf00decb.png)
object1、object2是NSObject的instance对象(实例对象)
- 它们是不同的两个对象,分别占据着两块不同的内存
2. class对象(类对象)
![](https://img.haomeiwen.com/i2058854/a7911bf8ca6503b4.png)
- objectClass1 ~ objectClass5都是NSObject的class对象(类对象)
- 它们是同一个对象。每个类在内存中有且只有一个class对象
class对象在内存中存储的信息主要包括:
- isa指针
- superclass指针
- 类的属性信息(@property)、
类的对象方法信息(instance method)
- 类的协议信息(protocol)、类的成员变量信息(ivar)
这里的属性是指它的类型、名等信息;
![](https://img.haomeiwen.com/i2058854/02fb80bc206e87cd.png)
3. meta-class对象(元类对象)
把类对象传进去,就可以获得元类对象
![](https://img.haomeiwen.com/i2058854/f1c4bdd1829fe60e.png)
- objectMetaClass是NSObject的meta-class对象(元类对象)
每个类在内存中有且只有一个meta-class对象
meta-class对象和class对象的内存结构是一样的,但是用途不一样,在内存中存储的信息主要包括
1.isa指针
2.superclass指针
3.类的类方法
信息(class method)
......
![](https://img.haomeiwen.com/i2058854/a1c9880cd26ea3b9.png)
以下代码获取的objectClass是class对象,并不是meta-class对象(通过class获得的都是类对象)
![](https://img.haomeiwen.com/i2058854/9050f4f8cc7c25f5.png)
![](https://img.haomeiwen.com/i2058854/02dfc907a3e2e59f.png)
三.isa指针
1. isa指针
![](https://img.haomeiwen.com/i2058854/ad3e994ac8ac42f7.png)
instance的isa指向class(类对象)
当调用对象方法时,通过instance的isa找到class(类对象),最后找到对象方法的实现进行调用
class(类对象)的isa指向meta-class(元类)
当调用类方法时,通过class(类对象)的isa找到meta-class(元类),最后找到类方法的实现进行调用
2. superclass
2.1 类对象的superclass指针
类对象的superclass指向其父类的类对象
;
如下:创建Person:NSObject;Student:Person
Student类对象superclass指向Person的类对象,Person类对象的superclass指向NSObject的类对象。
![](https://img.haomeiwen.com/i2058854/4013da2bcedb0032.png)
- superclass用处:
当Student的instance对象要调用Person的对象方法时,会先通过isa找到Student的class,然后通过superclass找到Person的class,最后找到对象方法的实现进行调用;
如下:student实例对象调用父类person的test方法。
student实例对象通过isa指针找到student类对象;
student类对象通过superclass找到person类对象;
调用person类对象里面的test方法。
int main(int argc, const char * argv[]) {
@autoreleasepool {
Student *student = [[Student alloc] init];
[student test];
[student personInstanceMethod];
[student init];
[Student studentClassMethod];
[Student personClassMethod];
[Student load];
[Student abc];
}
Person:
@interface Person : NSObject <NSCopying>
{
@public
int _age;
}
@property (nonatomic, assign) int no;
- (void)personInstanceMethod;
+ (void)personClassMethod;
@end
@implementation Person
- (void)test
{
}
- (void)personInstanceMethod
{
}
+ (void)personClassMethod
{
}
- (id)copyWithZone:(NSZone *)zone
{
return nil;
}
@end
Student:
@interface Student : Person <NSCoding>
{
@public
int _weight;
}
@property (nonatomic, assign) int height;
- (void)studentInstanceMethod;
+ (void)studentClassMethod;
@end
@implementation Student
- (void)test
{
}
- (void)studentInstanceMethod
{
}
+ (void)studentClassMethod
{
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
return nil;
}
- (void)encodeWithCoder:(NSCoder *)aCoder
{
}
@end
return 0;
}
2.2 元类对象的superclass指针
meta-class(元类)对象的superclass指针,指向父类的元类对象
![](https://img.haomeiwen.com/i2058854/d89e65afcc5ba7c7.png)
-superclass指针用处:
当Student的class要调用Person的类方法时,会先通过isa找到Student的meta-class,然后通过superclass找到Person的meta-class,最后找到类方法的实现进行调用
如上面的例子中:
Student调用Person的类方法personClassMethod: [Student personClassMethod];
Student类对象通过isa指针找到Student的元类对象;
Student的元类对象通过superclass指针找到Person的元类对象;
3. 方法的调用流程:
![](https://img.haomeiwen.com/i2058854/1cecfe29e6f550b7.png)
isa:
- instance(实例对象)的isa指向class(类对象)
- class(类对象)的isa指向meta-class(元类对象)
- meta-class(元类对象)的isa指向基类的meta-class(元类对象)
- 基类的元类对象的isa指向自己(基类的元类对象)
superclass:
- class(类对象)的superclass指向父类的class(类对象)
如果没有父类,superclass指针为nil- meta-class(元类)的superclass指向父类的meta-class(元类)
-基类的meta-class(元类对象)的superclass指向基类的class(类对象)
instance调用对象方法的轨迹
isa找到class,方法不存在,就通过superclass找父类
class调用类方法的轨迹
isa找meta-class,方法不存在,就通过superclass找父类
四. Class结构
-
类对象的地址:
实例对象的isa指针,指向类对象。那么isa的地址就是类对象的地址。但是从64bit开始,isa需要进行一次位运算(isa的地址&ISA_MASK),才能计算出类对象的真实地址。
-
元类对象的地址:
类对象的isa指针,指向元类对象。但是从64bit开始,isa需要进行一次位运算(isa的地址&ISA_MASK),才能计算出元类对象的真实地址。
![](https://img.haomeiwen.com/i2058854/fcb8adc987231cf5.png)
![](https://img.haomeiwen.com/i2058854/de280c821a8862fa.png)
struct objc_class
- class、meta-class对象的本质结构都是struct objc_class
objc4源码下载:https://opensource.apple.com/tarballs/objc4/
![](https://img.haomeiwen.com/i2058854/794b0478b188cc22.png)
五:总结
- 一个NSObject对象占用多少内存?
系统分配了16个字节给NSObject对象(通过malloc_size函数获得)
但NSObject对象内部只使用了8个字节的空间(64bit环境下,可以通过class_getInstanceSize函数获得)
- 对象的isa指针指向哪里?
instance对象的isa指向class对象
class对象的isa指向meta-class对象
meta-class对象的isa指向基类的meta-class对象
- OC的类信息存放在哪里?
instance对象:存放成员变量的具体值
类对象中:对象方法、属性、成员变量、协议信息
元类对象中:类方法
方法的调用轨迹:
- instance调用对象方法的轨迹
isa找到class,方法不存在,就通过superclass找父类- class调用类方法的轨迹
isa找meta-class,方法不存在,就通过superclass找父类
网友评论