RunTime

作者: 迷路的杰克 | 来源:发表于2019-08-13 11:41 被阅读0次

Associated Objects 关联对象

extension UIViewController {
    struct AssocateKeys {
        static var DescriptiveName = "nsh_DescriptiveName"
    }
    
    var descriptionName: String? {
        get {
            return objc_getAssociatedObject(self, &AssocateKeys.DescriptiveName) as? String
        }
        
        set {
            if let newValue = newValue {
                objc_setAssociatedObject(self, &AssocateKeys.DescriptiveName, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
            }
        }
    }
}

let vc = UIViewController()
vc.descriptionName = "Jack"
print(vc.descriptionName ?? "")

Method Swizzling 交换方法

其中要注意

  • swizzling 应该保证只会执行一次.
  • swizzling 应该在加载所有类的时候调用.
protocol SelfAware: class {
    static func awake()
    static func swizzlingForClass(_ forClass: AnyClass, originalSelector: Selector, swizzledSelector: Selector)
}

extension SelfAware {
    static func swizzlingForClass(_ forClass: AnyClass, originalSelector: Selector, swizzledSelector: Selector) {
        let originalMethod = class_getInstanceMethod(forClass, originalSelector)
        let swizzledMethod = class_getInstanceMethod(forClass, swizzledSelector)
        
        guard (originalMethod != nil && swizzledMethod != nil) else {
            return
        }
        
        if class_addMethod(forClass, originalSelector, method_getImplementation(swizzledMethod!), method_getTypeEncoding(swizzledMethod!)) {
            class_replaceMethod(forClass, swizzledSelector, method_getImplementation(originalMethod!), method_getTypeEncoding(originalMethod!))
        } else {
            method_exchangeImplementations(originalMethod!, swizzledMethod!)
        }
    }
}

class NothingToSeeHere {
    static func harmlessFunction() {
        let typeCount = Int(objc_getClassList(nil, 0))
        let types = UnsafeMutablePointer<AnyClass>.allocate(capacity: typeCount)
        let autoreleasingTypes = AutoreleasingUnsafeMutablePointer<AnyClass>(types)
        objc_getClassList(autoreleasingTypes, Int32(typeCount))
        
        for index in 0..<typeCount {
            (types[index] as? SelfAware.Type)?.awake()
        }
    }
}

extension UIApplication {
    private static let runOnce: Void = {
        NothingToSeeHere.harmlessFunction()
    }()
    
    open override var next: UIResponder? {
        UIApplication.runOnce
        return super.next
    }
}

在SelfAware的extension中为swizzlingForClass做了默认实现,相当于一层封装.

extension UIViewController: SelfAware {
    static func awake() {
        swizzleMethod
    }
    
    private static let swizzleMethod: Void = {
        let originalSelector = #selector(viewWillAppear(_:))
        let swizzledSelector = #selector(swizzled_viewWillAppear(_:))
        
        swizzlingForClass(UIViewController.self, originalSelector: originalSelector, swizzledSelector: swizzledSelector)
    }()
    
    @objc func swizzled_viewWillAppear(_ animated: Bool) {
        
        self.swizzled_viewWillAppear(animated)
        print("swizzled_viewWillAppear")
    }
}

这样就替换了 UIViewController的viewWillAppear方法

参考链接:
Dariel
swift-objc-runtime

相关文章

网友评论

      本文标题:RunTime

      本文链接:https://www.haomeiwen.com/subject/yzjvjctx.html