Runtime在Swift中的用法

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()方法的替代

iOS --- 如何在Swift項目中使用runtime?

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章