Swift中如何访问@propertyWrapper的argument参数?
问题描述
现有如下Swift代码:
@propertyWrapper struct Argument { var wrappedValue: Int? var argument: String } struct Model { @Argument var property: Int? @Argument(argument: "bar") var foo: Int? = nil } extension Model { init(property: Int, argument: String = "hello") { _property = Argument(wrappedValue: property, argument: argument) } } class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() let model = Model(property: 5) print(model) } }
输出结果:
Model(_property: propertyWrapper.Argument(wrappedValue: Optional(5), argument: "hello"), _foo: propertyWrapper.Argument(wrappedValue: nil, argument: "bar"))
可以看到,打印时能访问到@propertyWrapper的argument参数,但model.property和model.foo的类型仅为Int?,无法直接通过model.property.argument获取参数值。想要实现如下效果:
print(model.property.argument) // 打印"hello" print(model.foo.argument) // 打印"bar"
请问这是否可行?如何实现?
解决方案
方案1:使用Swift默认的投影值(推荐,符合语言设计规范)
Swift的属性包装器默认会生成一个投影值(以$开头),通过这个投影值可以直接访问包装器实例的所有属性,无需修改原有代码结构:
let model = Model(property: 5) print(model.$property.argument) // 输出"hello" print(model.$foo.argument) // 输出"bar"
这种方式是Swift官方推荐的访问属性包装器内部属性的方式,简洁且符合语言规范。
方案2:修改包装器,让wrappedValue返回包含值和参数的自定义类型
如果一定要实现model.property.argument的写法,可以调整Argument包装器的设计,让wrappedValue返回一个同时包含可选整数和argument属性的自定义类型,同时支持隐式转换为Int?,保证原有用法不变:
@propertyWrapper struct Argument { private var value: Int? let argument: String var wrappedValue: WrappedValue { WrappedValue(value: value, argument: argument) } // 自定义包装值类型 struct WrappedValue { let value: Int? let argument: String // 支持直接当作Int?使用 var intValue: Int? { value } } // 初始化方法适配原有代码 init(wrappedValue: Int?, argument: String = "") { self.value = wrappedValue self.argument = argument } init(argument: String) { self.value = nil self.argument = argument } } // 调整Model的属性类型 struct Model { @Argument var property: Argument.WrappedValue @Argument(argument: "bar") var foo: Argument.WrappedValue = Argument.WrappedValue(value: nil, argument: "bar") } extension Model { init(property: Int, argument: String = "hello") { _property = Argument(wrappedValue: property, argument: argument) } } // 使用示例 let model = Model(property: 5) print(model.property.argument) // 输出"hello" print(model.foo.argument) // 输出"bar" // 依然可以获取原始Int?值 if let propertyValue = model.property.intValue { print("Property value: \(propertyValue)") // 输出"Property value: 5" }
这种方式虽然实现了需求,但会增加代码复杂度,偏离Swift属性包装器的常规用法,建议优先使用方案1。
内容的提问来源于stack exchange,提问作者Makalele
相关产品推荐
相关产品推荐

