當咱們對A類添加監聽的時候,系統會自動生成一個NSKVONotifying_A的子類,這個類重寫了A的class、superclass、deealloc方法和該屬性的Set方法,同時A類的對象的isa指針指向了該虛擬子類。當監聽屬性改變的時候系統調用NSSetobjectValueandNotify,這個方法的執行流程是(willchangeValueforkey->改變父類的值->didchangeValueforkey->observeValueForKey:ofObject:change:context:),若是設置automaticallyNotifiesObserversForKey:(NSString *)key爲NO的時候則須要手動觸發KVO即手動調用willchangeValueforkey和didchangeValueforkey.html
func _NSSetObjectValueAndNotify {
...
willchangeValueforkey
...
" objc_msgSendSupper '改變父類的值(猜想這樣實現) "
...
didchangeValueforkey
...
observeValueForKey:ofObject:change:context:
}
複製代碼
由於該子類爲系統自動生成蘋果想假裝成並無這個類 因此重寫class/superclass ,可是調用 objc_getClass()這個方法時候依然會暴露,由於這個方法是調用調用對象的isa指針指向。dealloc則是系統還有一些其餘的事情處理c++
KVCKVC是由NSKeyValueCoding非正式協議實現的一種機制,對象採用該協議來提供對其屬性的間接訪問。當一個對象符合鍵值編碼時,它的屬性能夠經過一個簡潔、統一的消息傳遞接口經過字符串參數來尋址。這種間接訪問機制補充了實例變量及其關聯的訪問方法所提供的直接訪問。json
set value:for key:的默認實現:給定key和value參數做爲輸入,嘗試在接收調用的對象內,使用如下過程將名爲key的屬性設置爲value(對於非對象屬性,則設置未包裝的value版本,如表示非對象值:設計模式
OC的代碼分爲編譯時和運行時,Runtime是運行時處理oc的各個事件,好比動態添加類添加屬性,以及他的底層是一套C和C++還有彙編的api. OC的消息調用底層調用時objc_msgSend,這個消息流程是有兩種方式一種是快速發送一種是慢速發送,類的本質是結構體,他的構成有 isa和class_rw_t和class_data_bits_t的結構體、superclass,以及cache類,類結構裏的cache_t緩存存儲方法的Selector和IMP,它們組成一張哈希表,經過哈希表查找很是快,當查找的時候若是cache裏面存在則會直接返回,不存在的話則會進入慢速發送,找到了會在緩存裏面存一份。
快速查找:objc_msgSend是由彙編進行的他的過程是 先是優化isa指針,優化完畢後執行CacheLookup Normal,在CacheLookup裏進行CacheHit若是緩存裏有則會返回imp,沒有的話則會繼續走 checkmiss(checkmiss發送objc_msgSend_uncached)消息,處理完後執行add,,將查找到的消息放到緩存裏面,
慢速查找:objc_msgSend_uncached是一個結構體裏面調用了 MethodTableLookup 方法列表查找,而後經過br x 17 返回當前imp,MethodTableLookup內部方法是執行了 這個方法裏面有一個**__class_lookupMethodAndLoadCache3**,這個方法是_class_lookupMethodAndLoadCache3的彙編方法,當調用這個方法的時候的到了c++的lookUpImpForward,這個方法顯示聲明瞭一系列的初始化操做,經過遞歸先查找自身類若是自身類存在則返回,若是不存在則查找父類,直道爲nil爲止,中間若是查找到則返回並緩存一份經過log_and_fill_cache,若是都沒有則進入動態方法解析流程
動態消息解析: 當調用者自身和父類沒有實現方法時候會地用 _class_resolveMethod 方法這個方法裏面若是是類方法則執行resolveClassmethod(這個方法實際上是元類的resolveinstancemethod),而後一直調到根源類的父類NSObject。若是是實例方法則直接調用resolveinstancemethod,若是有處理則處理,若是未處理則調用__objc_msgForward_impcache,由於蘋果的這裏面實現是閉源的,能夠經過instrumentObjcMessageSends這個函數來進行查找,找到對應路徑會發現調用順訊就是 forwardTrage和methodSignutre 最後未處理執行doesnotGesture。若是沒有處理的話彙編後面還會調用 __objc_forward_handler來進行處理這個方法是打印出了出錯的堆棧信息。api
block匿名函數,分爲堆block,棧block和全局block,若是block未引用任何變量那麼他是一個全局block,若是未出做用域則是棧block,若引用了外界屬性,那麼他是一個堆block,block默認是存儲在堆裏的,ARC環境下回 自動執行copy操做。block的本質是 __main_block_impl_0 結構體裏面的結構是isa指針指向堆內存或者棧內存或者全局內存和 flag參數,isa指針指向本身的類(global malloc stack),有desc結構體描述block的信息,數組
Block不容許修改外部變量的值。這裏所說的外部變量的值,指的是棧中指針的內存地址。__block所起到的做用就是隻要觀察到該變量被block所持有,就將「外部變量」在棧中的內存地址放到了堆中。進而在block內部也能夠修改外部變量的值。 block對一個值進行引用時他會拷貝到一個新的內存地址,所以他修改的值不是原來的外部變量地址,而是修改了外部變量copy到的新的內存地址,不影響舊的。block以後再訪問其實訪問的其實訪問的是拷貝完以後的內存地址。
那麼 __block作的什麼操做,__Block_byref_a_0 這個指針獲取到了外部參數(棧區)的地址,而後下面的block傳入的是__Block_byref_a_0類型的指針地址,他再也不是原來的棧區的地址,所以能夠在閉包裏訪問到外部變量,那麼出block做用域後 __Block修飾的變量內存地址已經爲新的了因此在此訪問就是訪問的新內存空間緩存
Runtime維護了一個weak表,weak是一個哈希表,key是對象地址,value是weak指針的數組 當對一個屬性進行weak修飾時 會先調用objc_initweak,初始化一個新的weak指針指向地址,添加引用時調用objcstroeweak函數,這個函數是更新指針指向,釋放時調用cleardeallocing函數,該函數會搜索以該對象內存地址爲key,對應的全部value(weak指針數組)並將其置爲nil,後從entry從weak表中刪除。清理對象記錄。安全
通知一對多,代理一對一,通知基於觀察者實現。bash
通知只能通知不能接受回調,代理能夠反向通知數據結構
delegate運行成本低,block的運行成本高。**block出棧須要將使用的數據從棧內存拷貝到堆內存,固然對象的話就是加計數,使用完或者block置nil後才消除。delegate只是保存了一個對象指針,直接回調,沒有額外消耗。就像C的函數指針,只多作了一個查表動做。
delegate更安全些,好比: 避免循環引用。使用 block 時稍微不注意就造成循環引用,致使對象釋放不了。這種循環引用,一旦出現就比較難檢查出來。而 delegate 的方法是分離開的,並不會引用上下文,所以會更安全些。
這個類是一個JSON結構體初始化的時候能夠傳入object、string、dictionary等其餘操做單最後的數據結構都是有一個 ojbect 來進行初始化,而且定義有各個類型dictiorary string array bool int double,同時還支持路徑訪問,經過merge操做合併json,若是對象是數組則直接進行append操做,若是是字典則對字典的key進行賦值,原有則覆蓋,若是value是數組則進行遞歸調用
oc類的本質是結構體,他的結構是裏面有 isa指針,supeprcalss,cache類,data,class_rw_t,class_ro_t, data裏面是這個類全部的數據,包括方法列表屬性列表接口列表,由class_rw_t,和class_ro_t進行維護。
他初始化經過oc源碼NSObject.mm 文件能夠看到 當進行初始化操做的時候先執行 _objc_rootAlloc ==》callAlloc ==》 class_createInstance ==》 _class_createInstanceFromZone ==》_objc_constructOrFree 得到該對象,完成後還會執行init操做,而init方法調用**_objc_rootInit**,返回了自身
是由於,oc對象的init方法採用了 簡單工廠設計模式,他只須要設計一個init功能,由子類進行初始化從而獲得不一樣的對象。這個須要經過Swift的源碼進行源碼分析,這個我暫時還沒找到相關方面。