使用场景:
当我们在多个属性的get和set的方法里做了相同的事情,可以将其进行封装,简化代码。
举例:
string截取:
@propertyWrapper
struct TruncateWrapper {
private var value = ""
var wrappedValue: String {
set { value = truncate(newValue) }
get { value }
}
private func truncate(_ str: String) -> String {
if str.count > 10 {
return "\(str.prefix(10))..."
}
return str
}
}
class A {
@TruncateWrapper var str1: String
}
let _a = A()
_a.str1 = "123456789123456789"
print(_a.str1) //1234567891...
使用要点:
- 使用@propertyWrapper修饰封装结构体(类也可以)
- 封装结构体要包含名为wrappedValue的属性
- 使用@TruncateWrapper(封装结构体名)修饰被封装属性,@TruncateWrapper只能用来修饰类成员变量,不能修饰局部变量和全局变量
实现原理伪代码:
class A {
private var _str1: TruncateWrapper = TruncateWrapper()
var str1: String {
set { _str.wrappedValue = newValue }
get { _str.wrappedValue }
}
}
上述代码可以达到同样的效果,@propertyWrapper是语法糖。
进阶1:三种初始化方式
@propertyWrapper
struct TruncateWrapper {
private var value = ""
var wrappedValue: String {
set { value = truncate(newValue) }
get { value }
}
var count: Int = 10
var projectedValue: Int {
set { count = newValue }
get { count }
}
//支持含蓄式初始化方式
init() {
}
//支持赋值式初始化方式
init(wrappedValue: String) {
self.wrappedValue = wrappedValue
}
//支持灵活式初始化方式
init(wrappedValue: String, count: Int) {
self.count = count
self.wrappedValue = wrappedValue
}
private func truncate(_ str: String) -> String {
if str.count > count {
return "\(str.prefix(count))..."
}
return str
}
}
class A {
@TruncateWrapper var str1: String
@TruncateWrapper var str2: String = "123456789123456789"
@TruncateWrapper(wrappedValue: "123456789123456789", count: 5) var str3: String
}
let _a = A()
_a.str1 = "123456789123456789"
print(_a.str1) //1234567891...
print(_a.str2) //1234567891...
print(_a.str3) //12345...
进阶2:可以提供一个投影属性来暴露API
@propertyWrapper
struct TruncateWrapper {
private var value = ""
var wrappedValue: String {
set { value = truncate(newValue) }
get { value }
}
var count: Int = 10
var projectedValue: Int {
set { count = newValue }
get { count }
}
//支持含蓄式初始化方式
init() {
}
//支持赋值式初始化方式
init(wrappedValue: String) {
self.wrappedValue = wrappedValue
}
//支持灵活式初始化方式
init(wrappedValue: String, count: Int) {
self.count = count
self.wrappedValue = wrappedValue
}
private func truncate(_ str: String) -> String {
if str.count > count {
return "\(str.prefix(count))..."
}
return str
}
}
class A {
@TruncateWrapper var str1: String
@TruncateWrapper var str2: String = "123456789123456789"
@TruncateWrapper(wrappedValue: "123456789123456789", count: 5) var str3: String
}
let _a = A()
_a.str1 = "123456789123456789"
print(_a.str1) //1234567891...
print(_a.str2) //1234567891...
print(_a.str3) //12345...
_a.$str1 = 3
_a.str1 = "123456789123456789"
print(_a.str1) //123...
使用要点:
- 封装结构体要包含名为projectedValue的属性
- 通过$符访问被封装属性
swiftUI Combine中的 @State,@Binding,@ObjectBinding @EnvironmentObject等都是被@propertyWrapper修饰的struct类型。
参考链接: