如何使Swift.print复杂化(items:separator:terminator)

时间:2019-01-01 07:07:57

标签: ios swift method-swizzling

我正在寻找使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)
}

那有可能吗? obj-c运行时功能令人毛骨悚然。

2 个答案:

答案 0 :(得分:3)

方法混乱是一种Objective-C功能,使您可以在运行时交换方法的实现。为此,您需要一个@objc继承的NSObject对象。您需要一种方法

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

总而言之,没有办法使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

有关更多详细信息,请参见Remove println() for release version iOS Swift

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

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

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

通常,我建议您实施自定义日志记录系统,并通过其他方式(例如,代码审查或棉绒规则(例如swiftlint)。

答案 1 :(得分:0)

通过AlexanderCarpsen90添加评论

方法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时,您必须选择正确的方法enter image description here

输出

*****Hello World