我正在查看ThemeKit主题库的 Swift 代码。
特别是我想了解NSColor+ThemeKit.swift 中的以下代码:
// ThemeKit.set() replacement to use theme-aware color
@objc public func themeKitSet() {
// call original .set() function
themeKitSet()
// check if the user provides an alternative color
if ThemeManager.shared.isEnabled && isThemeOverriden {
// call ThemeColor.set() function
ThemeColor.color(with: Selector(colorNameComponent)).set()
}
}
似乎有一个无休止的递归调用,但大概不可能,因为代码工作正常。这通过在调用上设置断点来确认themeKitSet()
。无法单步执行调用并且不递归地继续执行。
在文件的前面有以下调用:
swizzleInstanceMethod(cls: NSClassFromString("NSDynamicSystemColor"), selector: #selector(set), withSelector: #selector(themeKitSet))
在NSObject+ThemeKit.swift 中的实现如下:
/// Swizzle instance methods.
@objc internal class func swizzleInstanceMethod(cls: AnyClass?, selector originalSelector: Selector, withSelector swizzledSelector: Selector) {
guard cls != nil else {
print("Unable to swizzle \(originalSelector): dynamic system color override will not be available.")
return
}
// methods
let originalMethod = class_getInstanceMethod(cls, originalSelector)
let swizzledMethod = class_getInstanceMethod(cls, swizzledSelector)
// add new method
let didAddMethod = class_addMethod(cls, originalSelector, method_getImplementation(swizzledMethod!), method_getTypeEncoding(swizzledMethod!))
// switch implementations
if didAddMethod {
class_replaceMethod(cls, swizzledSelector, method_getImplementation(originalMethod!), method_getTypeEncoding(originalMethod!))
} else {
method_exchangeImplementations(originalMethod!, swizzledMethod!)
}
}
我怀疑这是魔法的原因,但我对 Swift 和 Objective-C 的有限理解让我失望。
这里发生了什么?为什么表面上的递归调用实际上不是递归的?
您正确地识别了魔法位:它被称为方法调配,它是一种批量替换现有方法实现的方式。
当方法 swizzling 时,您会themeKitSet
经常看到这种看似递归的模式:该调用实际上运行了原始实现,如注释所述。这是因为 swizzling交换了两种方法的实现,在本例中为themeKitSet
和NSDynamicSystemColor.set
。
因此,post-swizzleNSDynamicSystemColor.set
运行您在那里看到的代码,并themeKitSet
成为原始实现。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句