iOS底层知识点总结
iOS 底层知识
总结一些零碎底层知识点
NSObject 对象内存占用分析
strut 8个字节int 4 个字节
指针 8 个字节
NSObject 系统分配 16 个字节,但 ivar 只占用 8 个字节,剩余 8 个字节空余。
结构体在内存中占用,是最大成员所占空间的倍数。
底层内存分配,分块分配按 16 的倍数
创建一个实例对象,至少需要多少内存?
1 | #import <objc/runtime.h> |
创建一个实例对象,实际分配了多少内存?
1 | #import <malloc/malloc.h> |
OC 对象有三种
实例对象 instance
NSObject *obj = [[NSObject alloc] init]
存储 isa 指针、其它成员变量类对象 class
Class *c = object_getClass(obj)Class *c = [NSObject class]
存储 isa 指针,superclass,属性信息(@property),对象方法,协议(protocol),成员变量(ivar)
每个类在内存中有且只有一个类对象信息。元类对象 meta-class
Class *meta_class = object_getClass(c)Class *meta_class = objec_getClass([NSObject class])
存储 isa 指针,superclass,类方法列表
每个元类对象在内存只有一个。
isa 与 superclass 指向

KVO 实现
- 利用 runtime 动态生成监听对象的派生类(NSKVONotifying_XXX),一个全新子类,使 instance 的 isa 指向该子类
- 当修改 instance 对象属性时,会调用该子类重写的属性的 set 方法
- set 方法会调用
Foundation的_NSSetXXXValueAndNotify方法 -
willChangeValueForKey: - 父类原来的
set方法 -
didChangeValueForKey:内部触发监听器的监听方法observeValueForKeyPath:ofObject:change:content:
手动调用
willChangeValueForKey:和didChangeValueForKey:可以手动触发 KVO
NSKVONotifying_XXX 内部结构
isa指向派生类自己的 metaClasssuperClass指向原来的类- (void)setXXX:重写的方法,内部调用_NSSetXXXValueAndNotify- (Class)class重写的方法,返回原来的类,目的为了隐藏派生类,隐藏 KVO 内部实现- (void)dealloc_isKVOA
KVC
调用
setValue: forKey:setValue: forKeyPath:可以触发 KVO
setValue: forKey: 实现原理

valueForKey:实现原理

load 方法
在 runtime 加载类、分类时调用,只调用一次
根据方法的地址,直接调用
首先调用所有类的 load 方法
按编译顺序调用(先编译,先调用)
调用子类的 load 方法之前会先调用父类的 load 方法再调用分类的 load 方法
按编译顺序调用(先编译,先调用)


initialize 方法
在第一次接收到消息时调用
使用objc_msgsend调用
没有实现就不会调用
- 先调用父类,再调用自己
- 如果分类实现了
initialize方法,会覆盖掉父类的实现(因为消息发送机制,分类->子类->父类) - 子类没有实现,会带调用父类的,可能会有多次调用,但只会初始化一次(消息发送机制)
关联对象
category 的底层结构
1 | struct category_t { |
由结构可知,分类无法添加成员变量,但是可以通过关联对象间接实现。
- 添加关联对象
1 | void objc_setAssociatedObject(id _Nonnull object, const void * _Nonnull key,id _Nullable value, objc_AssociationPolicy policy) |
- 获取关联对象
1 | id _Nullable objc_getAssociatedObject(id _Nonnull object, const void * _Nonnull key) |
- 移除所有关联对象
1 | void objc_removeAssociatedObjects(id _Nonnull object) |
关联对象的原理
四个核心对象
AssociationsManagerAssociationsHashMapObjectAssociationMapObjcAssociation
1 | class AssociationsManager { |
1 | typedef DenseMap<DisguisedPtr<objc_object>, ObjectAssociationMap> AssociationsHashMap; |
1 | typedef DenseMap<const void *, ObjcAssociation> ObjectAssociationMap; |
1 | class ObjcAssociation { |

- 关联对象不是存储在被关联对象的内存中。
- 关联对象存储在全局统一的
AssociationsManager中。 - 设置关联对象为 nil,相当于移除
AssociationMap中的所属项。 objc_removeAssociatedObjects相当于移除AssociationsHashMap的所属项目。