4

我正在寻找调配Swift.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)
}

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

4

2 回答 2

5

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

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)
}

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

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

#if !DEBUG

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

#endif

有关更多详细信息,请参阅发布版本 iOS Swift 的删除 println() 。

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

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

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

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

于 2019-01-01T19:13:59.110 回答
1

添加到AlexanderCarpsen90的评论中

Method Swizzling 是一个 Objective-C 运行时特性,它在 Swift 中本质上是不可用的,因为 Swift 不是一种动态语言。但是,您可以像在这个SO Post中那样拥有一个全局函数。下面是 Swift 4.2 的更新代码。但不幸的是,Swift.print如果函数名为print. 所以我将函数名称更改为logs

public func logs(items: Any..., separator: String = " ", terminator: String = "\n") {
    let output = items.map { "*\($0)"}.joined(separator: " ")
    Swift.print(output, terminator: terminator)
}

另一种可能的选择是将其放入协议中

public protocol CustomPrintable {
    func print(_ items: Any...)
}

extension CustomPrintable {
    func print(_ items: Any...) {
        let output = items.map { "*\($0)"}.joined(separator: " ")
        Swift.print("****" + output)
    }
}

用法

class SampleClass : CustomPrintable {

  func printValue() {
      print ("Hello World")
  }
}

但是这样函数就不再是全局函数了,在使用时print你必须选择正确的方法在此处输入图像描述

输出

*****Hello World
于 2019-01-01T16:18:20.910 回答