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

What are property wrappers in Swift? How to use @propertyWrapper?

2月21日 15:06

What are property wrappers in Swift? How to use @propertyWrapper?

Property wrappers in Swift are a mechanism for adding extra logic when setting and getting properties. Property wrappers can reuse property management logic and reduce code duplication.

Basic Property Wrapper:

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

Property Wrapper with Parameters:

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 }

Projected Value:

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

Common Property Wrapper Use Cases:

  1. Thread Safety:

    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. Lazy Loading:

    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. User Defaults:

    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) } } }

Best Practices for Property Wrappers:

  1. Use property wrappers to encapsulate repetitive property logic
  2. Use projected values to provide additional functionality
  3. Provide reasonable default values for property wrappers
  4. Be aware of the performance impact of property wrappers
  5. Use property wrappers where appropriate
标签:Swift