如何混合 Swift.print(items:separator:terminator)
How to swizzle Swift.print(items:separator:terminator)
我正在寻找调整 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
运行时特性。
添加评论
Method Swizzling 是一个 Objective-C 运行时特性,它在 Swift 中不可用,因为 Swift 不是动态语言。但是,您可以像 那样拥有一个全局函数。以下是 Swift 4.2 的更新代码。
但不幸的是,如果函数名称是 print
,它会调用原始的 Swift.print
函数。所以我把函数名改成了logs
public func logs(items: Any..., separator: String = " ", terminator: String = "\n") {
let output = items.map { "*\([=10=])"}.joined(separator: " ")
Swift.print(output, terminator: terminator)
}
另一种可能的选择是将其放入协议中
public protocol CustomPrintable {
func print(_ items: Any...)
}
extension CustomPrintable {
func print(_ items: Any...) {
let output = items.map { "*\([=11=])"}.joined(separator: " ")
Swift.print("****" + output)
}
}
用法
class SampleClass : CustomPrintable {
func printValue() {
print ("Hello World")
}
}
但是这样函数就不再是全局函数了,在使用 print
时你必须 select 正确的方法
输出
*****Hello World
方法调配是一项 Objective-C 功能,可让您在运行时交换方法的实现。为此,您需要一个继承自 NSObject
的 @objc
对象。你需要一个方法.
Swift.print
不是一种方法。它是在 Swift
模块中声明的函数。我们可以说它是全球性的,但它并不是真正的全球性。它是在模块 Swift
中定义的,它会自动导入到每个 Swift 代码中,因此您可以在没有 Swift.
前缀的情况下使用它。
综上所述,没办法swizzleSwift.print
.
你可以做的是隐藏使用你自己的实现的函数,也就是说,如果你在你自己的模块中声明一个同名的函数,那么当print
时,编译器会更喜欢你的函数,因为当前模块中的函数优先于其他模块(包括 Swift.
模块)中的函数。
public func print(_ items: Any..., separator: String = " ", terminator: String = "\n") {
let output = items.map { "\([=10=])" }.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.
模块内的标准库的任何命名冲突。
一般来说,我会建议实施您的自定义日志记录系统并通过其他方式强制使用它,例如代码审查或 linting 规则(例如 swiftlint)。
我正在寻找调整 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
运行时特性。
Method Swizzling 是一个 Objective-C 运行时特性,它在 Swift 中不可用,因为 Swift 不是动态语言。但是,您可以像 print
,它会调用原始的 Swift.print
函数。所以我把函数名改成了logs
public func logs(items: Any..., separator: String = " ", terminator: String = "\n") {
let output = items.map { "*\([=10=])"}.joined(separator: " ")
Swift.print(output, terminator: terminator)
}
另一种可能的选择是将其放入协议中
public protocol CustomPrintable {
func print(_ items: Any...)
}
extension CustomPrintable {
func print(_ items: Any...) {
let output = items.map { "*\([=11=])"}.joined(separator: " ")
Swift.print("****" + output)
}
}
用法
class SampleClass : CustomPrintable {
func printValue() {
print ("Hello World")
}
}
但是这样函数就不再是全局函数了,在使用 print
时你必须 select 正确的方法
输出
*****Hello World
方法调配是一项 Objective-C 功能,可让您在运行时交换方法的实现。为此,您需要一个继承自 NSObject
的 @objc
对象。你需要一个方法.
Swift.print
不是一种方法。它是在 Swift
模块中声明的函数。我们可以说它是全球性的,但它并不是真正的全球性。它是在模块 Swift
中定义的,它会自动导入到每个 Swift 代码中,因此您可以在没有 Swift.
前缀的情况下使用它。
综上所述,没办法swizzleSwift.print
.
你可以做的是隐藏使用你自己的实现的函数,也就是说,如果你在你自己的模块中声明一个同名的函数,那么当print
时,编译器会更喜欢你的函数,因为当前模块中的函数优先于其他模块(包括 Swift.
模块)中的函数。
public func print(_ items: Any..., separator: String = " ", terminator: String = "\n") {
let output = items.map { "\([=10=])" }.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.
模块内的标准库的任何命名冲突。
一般来说,我会建议实施您的自定义日志记录系统并通过其他方式强制使用它,例如代码审查或 linting 规则(例如 swiftlint)。