KVO 原理
里氏替換
- 利用runtime 動(dòng)態(tài)生成一個(gè)子類A节腐,且修改 instacne a對(duì)象的isa指向該全新子類
- NSKVONotifying_A 的屬性被修改時(shí)狼渊,子類的set方法內(nèi)部調(diào)用
willChangeValueForKey -> 原本的set實(shí)現(xiàn) -> didChangeValueForKey - didChangeValueForKey會(huì)調(diào)用監(jiān)聽(tīng)器的observeValueForKeyPath:ofObject:change:context:監(jiān)聽(tīng)方法
動(dòng)態(tài)生成的 NSKVONotifying_A 結(jié)構(gòu)體:有isa、superClass、setAge方法、class方法
setAge 方法:對(duì)觀察的變量重寫的set方法
class 方法:重寫掩缓,以隱藏自己的存在(返回再上一層)巡通,使 A 的實(shí)例調(diào)用 class 時(shí)仍返回 A 而非真實(shí)的 class NSKVONotifying_A
_isKVOA = YES;
dealloc 收尾方法重寫
- 手動(dòng)觸發(fā)KVO
調(diào)用willChangeValueForKey 和 didChangeValueForKey弥锄,缺一不可饭庞。
[p1 willChangeValueForKey:@“age”];
// do something
[p1 didChangeValueForKey:@“age”];
- 取消kvo
automaticallyNotifiesObserversForKey 返回NO
KVC 原理
- 先調(diào)用 setKey _setKey ,找了 直接調(diào)用
- 未找到 則 查看 accessInstanceVariablesDirectly 此方法是否可以直接訪問(wèn)成員變量 (默認(rèn)=YES)
- 可訪問(wèn) 按照 _key _isKey key isKey順序取賦值卤恳,未找到報(bào)錯(cuò) NSUnknownKeyException
- valueForKey類似
分類原理
- 分類文件在編譯后的底層結(jié)構(gòu)是 struct category_t劫窒,里面有分類的對(duì)象方法孕索,類方法,屬性,協(xié)議信息
- 在程序運(yùn)行階段,runtime將category的數(shù)據(jù),合并到類信息中(類對(duì)象,元類對(duì)象)
- 與類擴(kuò)展不同在于 一個(gè)編譯時(shí)合并ro,一個(gè)運(yùn)行時(shí)合并rw
- 后編譯的分類方法,在消息查找時(shí)會(huì)覆蓋前面的同名方法(原方法也還在)
分類添加弱引用對(duì)象 weak:加個(gè)obj,obj弱引用該對(duì)象
load 和 initialize
load
- +load 在 runtime 加載類阁猜,分類時(shí)調(diào)用
- 每個(gè)類民效,分類的 +load 運(yùn)行時(shí)只調(diào)用一次检吆,直接根據(jù)load方法地址調(diào)用摊灭,不走objc_msgSend
- 先調(diào)用類的 +load帚呼,先父類 再 子類
- 再調(diào)用分類的load,先編譯 先調(diào)用
initialize
- +initialize 在類第一次收到消息調(diào)用
- 先調(diào)用父類的 +initialize 柔袁,再調(diào)用子類 initialize
- +initialize通過(guò) objc_msgSend調(diào)用,如果子類未實(shí)現(xiàn) +initialize构回,會(huì)導(dǎo)致父類 initialize 多次調(diào)用
關(guān)聯(lián)對(duì)象
- 所有的關(guān)聯(lián)對(duì)象由全局對(duì)象 AssociationsManager管理,內(nèi)部有個(gè)hashMap map
- map使用 對(duì)象地址做為key 印蓖,ObejctAssociationMap 作為value
- ObejctAssociationMap 內(nèi)部也是屬性作為 key欠气,ObejctAssociation作為value
- ObejctAssociation內(nèi)部保存 策略 和 value
NSObject占用多少內(nèi)存
16字節(jié),因?yàn)閷?duì)象最少16字節(jié),一個(gè)指針是8字節(jié)(64位)
內(nèi)存對(duì)齊小結(jié)
- 前面的地址必須是后面的地址正數(shù)倍,不是就補(bǔ)齊
- 整個(gè)Struct的地址必須是最大字節(jié)的整數(shù)倍
在繼承條件下為
Person:isa 8字節(jié) + age 4字節(jié) + 內(nèi)存對(duì)齊 = 16字節(jié)
Student:isa 8字節(jié) + age 4字節(jié) + no 4字節(jié) (已對(duì)齊)= 16字節(jié)