Runtime是什麼?
- 運行時(Runtime)是指將數據類型的確定由編譯時推遲到了運行時
- Runtime是一套比較底層的純C語言API, 屬於1個C語言庫, 包含了很多底層的C語言API
- 平時編寫的OC代碼,在程序運行過程中,其實最終會轉換成Runtime的C語言代碼,Runtime是Object-C的幕後工作者
- Object-C需要Runtime來創建類和對象,進行消息發送和轉發
Runtime的典型事例
- 給系統分類添加屬性、方法
- 方法交換
- 獲取對象的屬性、私有屬性
- 字典轉換模型
- KVC、KVO
- 類的自我檢測
Swift中如何使用runtime
Swift代碼中已經沒有了Objective-C的運行時消息機制, 在代碼編譯時即確定了其實際調用的方法. 所以純粹的Swift類和對象沒有辦法使用runtime, 更不存在method swizzling.
爲了兼容Objective-C, 凡是繼承NSObject的類都會保留其動態性, 依然遵循Objective-C的運行時消息機制, 因此可以通過runtime獲取其屬性和方法, 實現method swizzling.
代碼實現:
extension UIViewController {
public class func loadMethodSwizzing(){
let originalSelector = #selector(UIViewController.viewDidAppear(_:))
let swizzledSelector = #selector(UIViewController.myMethod(animated:))
let originalMethod = class_getInstanceMethod(self, originalSelector)
let swizzledMethod = class_getInstanceMethod(self, swizzledSelector)
//在進行 Swizzling 的時候,需要用 class_addMethod 先進行判斷一下原有類中是否有要替換方法的實現
let didAddMethod: Bool = class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod!), method_getTypeEncoding(swizzledMethod!))
//如果 class_addMethod 返回 yes,說明當前類中沒有要替換方法的實現,所以需要在父類中查找,這時候就用到 method_getImplemetation 去獲取 class_getInstanceMethod 裏面的方法實現,然後再進行 class_replaceMethod 來實現 Method Swizzing
if didAddMethod {
class_replaceMethod(self, swizzledSelector, method_getImplementation(originalMethod!), method_getTypeEncoding(originalMethod!))
} else {
method_exchangeImplementations(originalMethod!, swizzledMethod!)
}
}
@objc func myMethod(animated: Bool) {
self.myMethod(animated: animated)
print("進入替換方法")
}
}
在APPdategate中添加
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
UIViewController.loadMethodSwizzing()
return true
}
參考blog:
Swift4.0中Runtime method_exchangeImplementations的使用和initialize()方法的替代