如何调配 Swift.print(items:separator:terminator)

Tal*_*ion 4 ios swift method-swizzling

我正在寻找 swizzleSwift.print功能的方法。覆盖它不是一种选择,因为如果您使用它可能会被绕过Swift.print(:)

选择器无法识别标识符:

@objc class func printSwizzle() {
    guard let instance = class_getInstanceMethod(self, #selector(print(separator:terminator:))),
    let swizzleInstance = class_getInstanceMethod(self, #selector(swizzlePrint(separator:terminator:))) else { return }
    method_exchangeImplementations(instance, swizzleInstance)
}
Run Code Online (Sandbox Code Playgroud)

这甚至可能吗?因为 swizzling 是一个obj-c运行时特性。

Sul*_*han 5

Method swizzling 是 Objective-C 的一项功能,它使您能够在运行时交换方法的实现。为此,您需要一个@objcNSObject. 你需要一个方法

Swift.print不是方法。它是在Swift模块中声明的函数。我们可以说它是全球性的,但它并不是真正的全球性。它是在模块内部定义的,Swift它会自动导入到每个 Swift 代码中,因此您可以在没有Swift.前缀的情况下使用它。

总之,没有办法 swizzle Swift.print

你可以做的是使用你自己的实现来隐藏那个函数,也就是说,如果你在你自己的模块中声明了一个同名的函数,那么当print被使用时,编译器会更喜欢你的函数,因为当前模块中的函数是优先于其他模块(包括Swift.模块)中的功能。

public func print(_ items: Any..., separator: String = " ", terminator: String = "\n") {
    let output = items.map { "\($0)" }.joined(separator: separator)
    Swift.print(output, terminator: terminator)
}
Run Code Online (Sandbox Code Playgroud)

您可以在其中使用任何您想要的逻辑。

使用它从生产中删除日志实际上很常见,例如:

#if !DEBUG

func print(_ items: Any..., separator: String = " ", terminator: String = "\n") {}
func debugPrint(_ items: Any..., separator: String = " ", terminator: String = "\n") {}

#endif
Run Code Online (Sandbox Code Playgroud)

有关更多详细信息,请参阅移除 println() 以获取发布版本 iOS Swift

本质上,您可以Swift通过在您的模块中重新声明它来隐藏整个模块,例如作为enum,因此禁用对 的调用Swift.print

enum Swift {
    public static func print(_ items: Any..., separator: String = " ", terminator: String = " ") {
        // do something
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,我通常建议不要这样做,因为很难解决与Swift.模块内部标准库的任何命名冲突。

一般而言,我建议实施您的自定义日志记录系统并通过其他方式强制其使用,例如代码审查或 linting 规则(例如 swiftlint)。