递归看起来 Swift 扩展函数,实际上不是。为什么不呢?



我正在查看 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 的有限理解让我失望了。

这是怎么回事?为什么表面上的递归调用实际上不是递归的?

您正确地识别了魔术位:它称为方法切换,它是一种批量替换现有方法实现的方法。

当方法旋转时,你会经常看到这种看似递归的模式:正如注释所说,themeKitSet调用实际上运行原始实现。这是因为滑动交换了两种方法的实现,在本例中为themeKitSetNSDynamicSystemColor.set.

因此,在 swizzle 之后,NSDynamicSystemColor.set运行您在那里看到的代码,themeKitSet已成为原始实现。

最新更新