文章分享至我的個人技術部落格: https://cainluo.github.io/15077238804616.html
講到這裡, RunTime
的知識點和應用基本上就已經講完了, 剩下的就靠大家自己在專案中的應用以及累積了.
這一篇文章主要是
轉載宣告:如需要轉載該文章, 請聯絡作者, 並且註明出處, 以及不能擅自修改本文.
RunTime基礎
基礎路徑圖:
在學習RunTime
的基礎時, 我們要搞清楚一些重要的東西, 一些專業術語:
- SEL
- id
- Class
- Method
- Ivar
- IMP
- Cache
- Property
我們可以從這些東西里獲取到指定類的所有資訊, 無論是公開的, 還是私有的, 全部都可以拿到, 並且操作.
PS: 但操作私有方法的時候, 注意不要用來上架, 除非你有方法讓蘋果稽核的時候通過.
RunTime進階
進階路徑圖:
在學習RunTime
進階的時候, 我們就要了解更加的深入.
訊息機制:
- objc_msgSend
- objc_msgSend_fpret
- objc_msgSend_stret
- objc_msgSendSuper
- objc_msgSendSuper_stret
物件關聯:
- objc_setAssociatedObject()
- objc_getAssociatedObject()
- objc_removeAssociatedObjects()
物件關聯的策略:
- OBJC_ASSOCIATION_ASSIGN
- OBJC_ASSOCIATION_RETAIN_NONATOMIC
- OBJC_ASSOCIATION_COPY_NONATOMIC
- OBJC_ASSOCIATION_RETAIN
- OBJC_ASSOCIATION_COPY
動態方法解析:
resolveInstanceMethod:
YES
, 通過class_addMethod
訊息得到處理, 結束NO
, 進入forwardingTargetForSelector
- 指定響應
selector
, 訊息得到處理, 結束 - 不指定響應
selector
- 進入
methodSignatureForSelector
, 指定方法簽名, 呼叫forwardInvovation
, 通過anInvocation
做處理, 訊息得到處理, 結束 - 不指定方法簽名, 該訊息沒有得到處理, 系統報錯
- 進入
- 指定響應
RunTime應用
應用路徑圖:
在學習完RunTime
之後, 我們就可以應用到我們的實際開發中.
Category
- 關聯物件
- 控制物件
Class
- 動態新增方法
- 動態交換方法
- 動態攔截並替換方法
- 動態給方法新增額外功能
Model
- 自動歸檔和解檔
- 自動字典轉模型
- 字典轉模型(模型屬性數量大於字典key數量)
- 字典轉模型(模型中巢狀模型)
- 字典轉模型(陣列中巢狀模型)
RunTime例項開發場景
在實際開發中, 我們有一些例項場景會用到RunTime
:
- 替換
ViewController
的宣告週期 - 解決集合類因索引的問題崩潰的問題
- 防止按鈕重複高強度點選
- 全域性更換控制元件初始效果
- App熱修復
- App異常載入的展點陣圖
- 全域性修改
UINavigationBar
的backButtonItem
Runtime Method Swizzling開發例項彙總
RunTime面試題及答案
問題: objc在向一個物件傳送訊息時, 發生了什麼? |
---|
1.根據物件的isa 指標找到類物件id , 在查詢類物件裡面的methodLists 方法函式列表 |
2.如果沒有在好到, 在沿著superClass , 尋找父類,再在父類methodLists 方法列表裡面查詢 |
3.最終找到SEL , 根據id 和SEL 確認IMP (指標函式), 在傳送訊息. |
問題: 什麼時候會報unrecognized selector 錯誤? iOS 有哪些機制來避免走到這一步? |
---|
1.當傳送訊息的時候, 我們會根據類裡面的methodLists 列表去查詢我們要動用的SEL , 當查詢不到的時候, 我們會一直沿著父類查詢 |
2.當最終查詢不到的時候我們會報unrecognized selector 錯誤, 當系統查詢不到方法的時候, 會呼叫+(BOOL)resolveInstanceMethod:(SEL)sel 動態解釋的方法來給我一次機會來新增, 呼叫不到的方法. |
3.或者我們可以再次使用-(id)forwardingTargetForSelector:(SEL)aSelector 重定向的方法來告訴系統,該呼叫什麼方法,一來保證不會崩潰. |
問題: 能否向編譯後得到的類中增加例項變數?能否向執行時建立的類中新增例項變數? 為什麼? |
---|
1.不能向編譯後得到的類增加例項變數. |
2.能向執行時建立的類中新增例項變數. |
解釋: |
1. 編譯後的類已經註冊在runtime 中,類結構體中的objc_ivar_list 例項變數的連結串列和instance_size 例項變數的記憶體大小已經確定,runtime 會呼叫class_setvarlayout 或class_setWeaklvarLayout 來處理strong``weak 引用.所以不能向存在的類中新增例項變數. |
2. 執行時建立的類是可以新增例項變數,呼叫class_addIvar 函式. 但是的在呼叫objc_allocateClassPair 之後,objc_registerClassPair 之前,原因同上. |
問題: runtime如何實現weak變數的自動置nil? |
---|
1.runtime 對註冊的類, 會進行佈局,對於weak 物件會放入一個hash 表中。 用weak 指向的物件記憶體地址作為key ,當此物件的引用計數為0 的時候會dealloc . |
2.假如weak 指向的物件記憶體地址是A ,那麼就會以A 為鍵, 在這個weak 表中搜尋,找到所有以A 為鍵的weak 物件,從而設定為nil . |
問題: 給類新增一個屬性後,在類結構體裡哪些元素會發生變化 |
---|
1.instance_size :例項的記憶體大小. |
2.objc_ivar_list *ivars : 屬性列表. |
總結
好了, 終於到尾聲了, 希望大家可以在我的文章裡學到知識, 早日迎娶白富美, 走上人生巔峰, 最後附上所有的文章: