我最近一直在尝试使用 swift 属性包装器,想知道是否有任何方法可以将它们组合在一起以实现更加模块化的架构。例如:
@WrapperOne @WrapperTwo var foo: T
浏览文档一无所获。如何做到这一点的唯一参考是在这个 GitHub 页面(https://github.com/apple/swift-evolution/blob/master/proposals/0258-property-wrappers.md)(下面的引用),这似乎说有可能的。其他文章说它们很难编写,但没有解释如何去做。但是,我无法对它做出正面或反面,如果有人可以向我展示一些关于如何实现它的示例代码(见帖子底部),我将不胜感激。
当为给定属性提供多个属性包装器时,包装器组合在一起以获得两种效果。例如,考虑 和 的
DelayedMutable
组成Copying
:@DelayedMutable @Copying var path: UIBezierPath
在这里,我们有一个属性,我们可以将初始化延迟到以后。当我们确实设置了一个值时,它将通过
NSCopying
的复制方法进行复制。组合是通过将后面的包装器类型嵌套在较早的包装器类型中来实现的,其中最内层的嵌套类型是原始属性的类型。对于上面的示例,后备存储将是类型DelayedMutable<Copying<UIBezierPath>>
,并且路径的合成 getter/setter 将查看 .wrappedValue 的两个级别:private var _path: DelayedMutable<Copying<UIBezierPath>> = .init() var path: UIBezierPath { get { return _path.wrappedValue.wrappedValue } set { _path.wrappedValue.wrappedValue = newValue } }
请注意,这种设计意味着属性包装器组合不是可交换的,因为属性的顺序会影响嵌套的执行方式: @DelayedMutable @Copying var path1: UIBezierPath // _path1 的类型为 DelayedMutable> @Copying @DelayedMutable var path2: UIBezierPath / /error: _path2 has ill-formed type Copying> 在这种情况下,类型检查器会阻止二次排序,因为
DelayedMutable
不符合NSCopying
协议。情况并非总是如此:一些语义不好的组合不一定会被类型系统捕获。在“考虑的替代方案”中介绍了这种组合方法的替代方案。
理想情况下,我想实现以下内容:
@propertyWrapper
struct Doubled {
var number: Int
var wrappedValue: Int {
get { (value * 2) }
set { value = Int(newValue / 2) }
}
init(wrappedValue: Int) {
self.number = wrappedValue
}
}
和
@propertyWrapper
struct Tripled {
var number: Int
var wrappedValue: Int {
get { (value * 3) }
set { value = Int(newValue / 3) }
}
init(wrappedValue: Int) {
self.number = wrappedValue
}
}
这样就可以实现:
@Tripled @Doubled var number = 5
我知道这个例子是实现属性包装器组合的一个有点愚蠢的理由,但这只是为了在学习新功能时简单起见。
任何帮助将不胜感激。