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
网友评论