乐闻世界logo
搜索文章和话题

Swift 中的属性包装器是什么?如何使用 @propertyWrapper?

2月21日 15:06

Swift 中的属性包装器是什么?如何使用 @propertyWrapper?

Swift 中的属性包装器是一种在属性设置和获取时添加额外逻辑的机制。属性包装器可以复用属性管理逻辑,减少代码重复。

基本属性包装器:

swift
@propertyWrapper struct TwelveOrLess { private var number: Int init() { self.number = 0 } var wrappedValue: Int { get { return number } set { number = min(newValue, 12) } } } struct SmallRectangle { @TwelveOrLess var height: Int @TwelveOrLess var width: Int } var rectangle = SmallRectangle() rectangle.height = 10 rectangle.width = 20 print(rectangle.width) // 12

带参数的属性包装器:

swift
@propertyWrapper struct SmallNumber { private var maximum: Int private var number: Int init(wrappedValue: Int, maximum: Int) { self.maximum = maximum self.number = wrappedValue } var wrappedValue: Int { get { return number } set { number = min(newValue, maximum) } } } struct ZeroRectangle { @SmallNumber(wrappedValue: 0, maximum: 5) var height: Int @SmallNumber(wrappedValue: 0, maximum: 10) var width: Int }

投射值:

swift
@propertyWrapper struct SmallNumber { private var number: Int init(wrappedValue: Int) { self.number = wrappedValue } var wrappedValue: Int { get { return number } set { number = min(newValue, 12) } } var projectedValue: Bool { return number > 12 } } struct SomeStructure { @SmallNumber var someNumber: Int } var someStructure = SomeStructure() someStructure.someNumber = 4 print(someStructure.$someNumber) // false someStructure.someNumber = 14 print(someStructure.$someNumber) // true

常见的属性包装器用例:

  1. 线程安全:

    swift
    @propertyWrapper struct ThreadSafe { private var value: T private let lock = NSLock() init(wrappedValue: T) { self.value = wrappedValue } var wrappedValue: T { get { lock.lock() defer { lock.unlock() } return value } set { lock.lock() defer { lock.unlock() } value = newValue } } }
  2. 延迟加载:

    swift
    @propertyWrapper struct Lazy { private var value: T? var wrappedValue: T { mutating get { if let value = value { return value } let initialValue = wrappedValueFactory() value = initialValue return initialValue } } let wrappedValueFactory: () -> T init(wrappedValue: @autoclosure @escaping () -> T) { self.wrappedValueFactory = wrappedValue } }
  3. 用户默认值:

    swift
    @propertyWrapper struct UserDefault { let key: String let defaultValue: T var wrappedValue: T { get { UserDefaults.standard.object(forKey: key) as? T ?? defaultValue } set { UserDefaults.standard.set(newValue, forKey: key) } } }

属性包装器的最佳实践:

  1. 使用属性包装器封装重复的属性逻辑
  2. 使用投射值提供额外的功能
  3. 为属性包装器提供合理的默认值
  4. 注意属性包装器的性能影响
  5. 在适当的地方使用属性包装器
标签:Swift