通过几道面试题我们来逐渐解开类与对象的本质。
1. 一个NSObject对象占用多少内存?
2. 对象isa指针指向哪里?
3. 什么是class、metaClass对象?
4. OC的类信息存放在哪里?
Object-C的本质
我们平时编写的Objective-C(后面简称OC)代码,其实底层都是C/C++代码
![](https://img.haomeiwen.com/i9521271/c2c638e8fdadf814.png)
我们来将OC代码转换为C/C++代码
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc 文件名 -o 输出的CPP文件
例如:xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main.cpp
@interface LPPerson : NSObject
{
@public
int _age;
NSString *_name;
}
@end
@implementation LPPerson
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
LPPerson *person = [[LPPerson alloc] init];
person->_age = 18;
person->_name = @"LP";
}
return 0;
}
我们来看一下源码
struct NSObject_IMPL {
Class isa;
};
struct LPPerson_IMPL {
struct NSObject_IMPL NSObject_IVARS;
int _age;
NSString *_name;
};
...
...
![](https://img.haomeiwen.com/i9521271/4b2052df968aaa44.png)
其实Class在runtime源码中定义 typedef struct objc_class *Class; 稍后我们会分析源码
所以,OC的对象、类都是基于C/C++当中结构体实现的
1. 一个NSObject对象占用多少内存?
答:可以看到NSObject_IMPL内部的isa是指向struct objc_class,说明isa是一个指针,在64位系统中
该对象占用8个字节,但是实际分配了16个字节。我们需要用到下面两个函数
创建一个实例对象,至少需要多少内存?
#import <objc/runtime.h>
class_getInstanceSize([NSObject class]);
创建一个实例对象,实际上分配了多少内存?
#import <malloc/malloc.h>
malloc_size((__bridge const void *)obj);
打印如下:
NSObject *obj = [[NSObject alloc] init];
NSLog(@"%zd",class_getInstanceSize([NSObject class]));
NSLog(@"%zd",malloc_size((__bridge void *const)obj));
OCDemo[25726:949760] 8
OCDemo[25726:949760] 16
实例对象、类、元类(instance、class、meta-class)
Objective-C的runtime是开源的,苹果开源官网下载:objc4。
实例对象:一个类的具体实例。
实例对象的结构体数据结构如下:
struct objc_object {
private:
isa_t isa;
public:
// ISA() assumes this is NOT a tagged pointer object
Class ISA();
// getIsa() allows this to be a tagged pointer object
Class getIsa();
...(省略)
}
NSObject *obj1 = [[NSObject alloc] init];
NSObject *obj2 = [[NSObject alloc] init];
object1、object2是NSObject的instance对象(实例对象)它们是不同的两个对象,分别占据着两块不同的内存
-
通过查看对象的底层代码,同样可以发现,对象在内存中的存储信息包含
-
isa指针
-
其它成员变量的值等
-
类:类是定义同一类所有对象的变量和方法的蓝图或原型(维基百科)
类的结构体数据结构如下:
struct objc_class : objc_object {
// Class ISA;
Class superclass;
cache_t cache; // formerly cache pointer and vtable
class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags
class_rw_t *data() {
return bits.data();
}
void setData(class_rw_t *newData) {
bits.setData(newData);
}
...(省略)
}
struct class_rw_t {
// Be warned that Symbolication knows the layout of this structure.
uint32_t flags;
uint32_t version;
const class_ro_t *ro;
method_array_t methods; // 类对象方法信息
property_array_t properties; // 属性信息
protocol_array_t protocols; // 协议信息
...(省略)
struct class_ro_t {
uint32_t flags;
uint32_t instanceStart;
uint32_t instanceSize; // 对象占用的内存大小
#ifdef __LP64__
uint32_t reserved;
#endif
const uint8_t * ivarLayout;
const char * name; // 类名
method_list_t * baseMethodList;
protocol_list_t * baseProtocols;
const ivar_list_t * ivars; // 成员变量列表
const uint8_t * weakIvarLayout;
property_list_t *baseProperties;
method_list_t *baseMethods() const {
return baseMethodList;
}
};
![](https://img.haomeiwen.com/i9521271/8b4edcb94088bdb0.png)
元类:元类其实就是描述类对象的类
NSObject *obj3 =[[NSObject alloc]init];
Class objMetaClass1 = objc_getMetaClass("NSObject");
Class objMetaClass2 = object_getClass([NSObject class]);
Class objMetaClass3 = object_getClass(object_getClass(obj3));
NSLog(@"%p %p %p",objMetaClass1,objMetaClass2,objMetaClass3);
OCDemo[2418:112622] 0x7fff97fdb0f0 0x7fff97fdb0f0 0x7fff97fdb0f0
objMetaClass1、objMetaClass2、objMetaClass3就是NSObject的meta-class对象(元类对象)
![](https://img.haomeiwen.com/i9521271/db206421a82f97ce.png)
BOOL isMetaClass = class_isMetaClass([NSObject class]); // 是否是元类
方法的调用流程
通过以上信息我们就了解到了类、对象、元类之间的关系,那么类方法和对象方法的调用过程是怎样的呢??如下图所示:
![](https://img.haomeiwen.com/i9521271/4b2b44c029e2f229.png)
-
isa指向
-
instance的isa指向class
-
当调用对象方法时,通过instance的isa找到class,最后找到对象方法的实现进行调用
-
-
class的isa指向meta-class
-
当调用类方法时,通过class的isa找到meta-class,最后找到类方法的实现进行调用
-
-
![](https://img.haomeiwen.com/i9521271/f993717f98aa2ee7.png)
-
class对象的superclass指针
-
当Student的instance对象要调用Person的对象方法时,会先通过isa找到Student的class,然后通过superclass找到Person的class,最后找到对象方法的实现进行调用
-
![](https://img.haomeiwen.com/i9521271/1635c7b8ec2c0b7d.png)
-
meta-class对象的superclass指针
-
当Student的class要调用Person的类方法时,会先通过isa找到Student的meta-class,然后通过superclass找到Person的meta-class,最后找到类方法的实现进行调用
-
isa、superclass总结
![](https://img.haomeiwen.com/i9521271/c37609d7d37cbcf4.png)
![](https://img.haomeiwen.com/i9521271/c3567c08ab0fe0fc.png)
网友评论