前言
- 本文只是作为自己对学习的一个总结,写了很久了一直放在印象笔记中,拿出来放在上,一方面可以温习一下,另一方面和大家共享学习经验,如果有错误的地方欢迎各位大神提出
- 文笔不行,可能会写的有点乱,请见谅!
我们用到的应该只有三种对象
- 实例对象 (instance)
- 类对象 (class)
- 元类对象(meta)
类对象(class)
我们可以通过源码-723对对象进行分析
类对象在objc-runtime-old.h的定义
struct objc_class : objc_object {
Class superclass;
const char *name;
uint32_t version;
uint32_t info;
uint32_t instance_size;
struct old_ivar_list *ivars;
struct old_method_list **methodLists;
Cache cache;
struct old_protocol_list *protocols;
}
在objc-runtime-new.h下就发生了变化,我们着重看新的
struct objc_object {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
};
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();
}
}
内部结构:
isa
: 指向元类的指针(因为objc_class继承自objc_object,所以内部也会有isa指针)当一个类对象调用某个方法的时候,会根据类对象的isa指针找到对应的元类对象,在元类对象的bits
里面找到类对象的方法的实现;
superclass
:父类类对象
cache
: 方法缓存
bits
: 类的详细信息(方法列表,协议列表,属性列表)
NSObject *objc = [[NSObject alloc]init];
Class class1 = [objc class];
Class class2 = [NSObject class];
Class class3 = objc_getClass("NSObject");
NSLog(@"objc = %p",objc);
NSLog(@"class1 =%p",class1);
NSLog(@"class2 =%p",class2);
NSLog(@"class3 =%p",class3);
一个类有且只有一个类对象:用来存储对象方法列表,协议列表,superclass,属性列表,成员变量信息
实例对象(instance)
创建一个Person类,继承自NSObject
@interface Person : NSObject
{
int _age;
int _num;
}
@end
@implementation Person
@end
用clang编译成C++代码,如下:
struct NSObject_IMPL {
Class isa;
};
struct Person_IMPL {
struct NSObject_IMPL NSObject_IVARS;
int _age;
};
从上可以看出一个实例对象也是一个结构体包含了:
-
isa
: 指向了类对象 -
_age
: 成员变量
记得以前和同事讨论过一个问题:类对象的内部有个properties
,是不是所有的属性都存储在这呢?如果是,那一个类可以创建多个对象,那每个对象的属性存储的值是不一样的,类对象内部是怎么进行存储的呢?我们用下面的例子实验一下
struct Person_IMPL{
Class isa;
int _age;
int _num;
};
Person *person = [[Person alloc]init];
person->_age = 20;
person->_num = 30;
Person *person2 = [[Person alloc]init];
struct Person_IMPL *personImpl = (__bridge struct Person_IMPL *)(person);
struct Person_IMPL *personImpl2 = (__bridge struct Person_IMPL *)(person2);
NSLog(@"age = %d num = %d",personImpl->_age,personImpl->_num);
NSLog(@"age = %d num = %d",personImpl2->_age,personImpl2->_num);
从上面的例子中,可以看出:对象成员变量的值是存储在实例对象的结构体中的,但是我还是有疑惑,既然对象的实例变量的值是存储在实例对象的结构体中的,类对象结构体中存储的properties ,ivars
是用来干描述信息的,只存储一份就够了;
总结一下: 实例对象中只存储了成员变量,不会存储方法,方法是存储在类对象和元类对象中的,以后的文章中会写到方法调用流程
一个对象占用多少内存呢?
Person *person = [[Person alloc]init];
NSLog(@"%zu",class_getInstanceSize([NSObject class]));
NSLog(@"%zu",class_getInstanceSize([person class]));
NSLog(@"%zu",malloc_size((__bridge const void *)(person)));
打印结果为: 8 , 16 ,16(64位架构下
)
NSObject对象占用8个字节,因为里面只有一个isa指针
person占用了16字节,因为person继承自NSObject,所以内部也会有isa指针,两个int成员共占用8字节,也就是16字节
元类对象(meta)
用来存储类方法的对象;怎么获取元类对象呢?
Class class1 = object_getClass([objc class]);
Class class2 = object_getClass([NSObject class]);
BOOL isMeta = class_isMetaClass(class1);
NSLog(@"class1 =%p class2 =%p ",class1,class2);
NSLog(@"class1 is meta = %d",isMeta);
class_isMetaClass(Class _Nullable cls)
:传入类对象返回元类对象,传入实例对象返回类对象
元类对象也是有且只有一个的,元类对象内部结构和类对象是一样的,因为他们都是Class类型的,只不过里面存储的内容不一样
OC中三种对象类型就上面这些了,后面的文章中还会进行详细点的讲解