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) |
关联对象的原理
四个核心对象
AssociationsManager
AssociationsHashMap
ObjectAssociationMap
ObjcAssociation
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
的所属项目。