最近忽然发现了一个swift的之前发布的feature,很有意思,之后开发可能用得到,记录一下。
@_dynamicReplacement(for:)
动态方法替换,需要swift版本5.1以上,这东西貌似是为了实现Xcode中swiftUI的preview而加进来的,不过既然加进来了,就肯定可以用来做其他的,举例如下。
class Person {
dynamic func say() {
print("hi")
}
}
extension Person {
@_dynamicReplacement(for: say)
func sayA() {
print("A1")
say()
print("A2")
}
}
Person().say()
// 输出 A1 hi A2
注意事项:
- 除非增加
-enable-implicit-dynamic
的编译标志(building setting -> swift compiler - Custom Flags -> Other Swift Flags),否则,被替换的方法需要被dynamic
标记,不然无法通过编译 - 在使用OC的运行时方法替换时,想要执行原方法,应该调用
sayA
,但在使用@_dynamicReplacement
时,直接调用say
就可以了
连环替换的场景
上面的情况看起来没有什么特殊的,我们看一下连环替换的场景
class Person {
dynamic func say() {
print("hi")
}
}
extension Person {
@_dynamicReplacement(for: say)
func sayA() {
print("A1")
say()
print("A2")
}
}
extension Person {
@_dynamicReplacement(for: say)
func sayB() {
print("B1")
say()
print("B2")
}
}
Person().say()
如果是OC的运行时实现方法替换,不难想象输出会是:
B1 - A1 - hi - A2 - B2
但在这里,会输出:
B1 - hi - B2
后声明的方法替换才会生效,但假如我们添加-Xfrontend
和-enable-dynamic-replacement-chaining
这两个编译标志后,就可以得到:
B1 - A1 - hi - A2 - B2
我这里只记录一下,具体的原理和分析可以看下下面的参考链接。