什么是@propertyWrapper(属性包装)

1,它类似Java等语言中的注解
2,它包装修饰属性的get set方法
3,目的在于封装属性操作,简化代码,降低重复书写概率

@propertyWrapper什么作用

预设场景

实际开发中,我们的默一个属性要求必须为两头去除空格的状态.
这时我们有两种方式实现
1, 重写get方法,每次get时都去除两头空格
2, 重写set方法,每次set时都去除两头空格
(对于以上方法,我们暂不讨论性能和业务贴合的问题.)

class Test {
    var whiteStr {
		set {
			// 去除空格操作
		}
		// 或者
		get {
			// 去除空格操作
		}
	}
}

这时我们会面临一个问题,如果有很多个属性都有这个要求
那么我们的代码就会变成

class Test {
    var whiteStr1 {
		set {
			// 去除空格操作
		}
		// 或者
		get {
			// 去除空格操作
		}
	}
	
    var whiteStr2 {
		set {
			// 去除空格操作
		}
		// 或者
		get {
			// 去除空格操作
		}
	}
	...
}

充其量我们把“去除空格操作”抽象提取出来,但也并不能降低多少代码重复率,还是在不停的写set get

这时@propertyWrapper的作用就提现出来了

它可以以下形式来编写:

class Test {
	@NoWhite() //“NoWhite”这个名字是我们自己定义的
    var whiteStr1 
    
	@NoWhite()
    var whiteStr2
    
	...
}

并且可以达到同样去除两头空格目的

@propertyWrapper怎么实现及实践

@propertyWrapper struct NoWhite {
    // 用来记录被包装属性的值
    // 可以是别的名字,比如model item等,value只是在此demo中的名字
    var value: String
    
    // 包装值,可以把它看成value的计算属性
    // 'wrappedValue' 这个名称不能更改,必须实现
    // 以上一段中的`whiteStr`为例
    // 被NoWhite修饰后, 操作`whiteStr`对应的get set 方法,实际是在操作wrappedValue的
    // get set 方法
    // 这里我们选用在set中处理两头空格的方式
    var wrappedValue: String {
        get { value }
        set {
            let whitespace = NSCharacterSet.whitespacesAndNewlines
            value = newValue.trimmingCharacters(in: whitespace)
        }
    }
    
    //  映射值
    //  被修饰的属性在属性名前加`$`符,调用的就是的projectedValue的get方法
    //  比如, self.$whiteStr
	//  当使用self.$whiteStr作为参数传递时,是引用传递. 
	//  使用self.whiteStr作为参数传递时,是值传递
 	var projectedValue: String {
        let whitespace = NSCharacterSet.whitespacesAndNewlines
        return value.trimmingCharacters(in: whitespace)
    }
    
    // 初始化方法
    init(wrappedValue initialValue: String = "") {
        value = initialValue
    }

}
class Test {
    @NoWhite()
    var whiteStr
}

te.whiteStr = " 123 " // 首位有空格

print(te.whiteStr) // "123"

print(te.whiteStr.count) // "3"

总结

1, @propertyWrapper的本质就是包装修饰属性的set get方法
2, @propertyWrapper的作用就是降低代码重复率
3, @propertyWrapper的应用中的projectedValue在SwiftUI的 @State中, 作为 @Binding 的修饰对象的引用传递来解决多层嵌套UI的状态同步问题.