# Custom Property Wrappers in SwiftUI

If you've used SwiftUI, you've definitely encountered property wrappers like `@State`, `@Binding`, and `@ObservedObject`. But have you ever wondered how they work, or how to create your own? In this article, we'll dive deep into property wrappers and learn how to make SwiftUI views react to our custom implementations.

## What is a Property Wrapper?

A property wrapper is a Swift language feature that adds a layer of separation between code that manages how a property is stored and the code that defines a property. Introduced in Swift 5.1, property wrappers allow you to write reusable property management logic once and apply it to multiple properties.

### Basic Property Wrapper Example

Here's a simple property wrapper that ensures a value stays within bounds:

```swift
@propertyWrapper
struct Clamped<Value: Comparable> {
    private var value: Value
    private let range: ClosedRange<Value>
    
    var wrappedValue: Value {
        get { value }
        set { value = min(max(range.lowerBound, newValue), range.upperBound) }
    }
    
    init(wrappedValue: Value, _ range: ClosedRange<Value>) {
        self.range = range
        self.value = min(max(range.lowerBound, wrappedValue), range.upperBound)
    }
}

// Usage
struct Settings {
    @Clamped(0...100) var volume: Int = 50
}
```

### Key Components of a Property Wrapper

1. **The `@propertyWrapper` attribute** - Marks a type as a property wrapper
2. **`wrappedValue` property** - The actual value being wrapped
3. **`init(wrappedValue:)`** - Initializer that accepts the initial value
4. **`projectedValue` (optional)** - Provides additional functionality, accessed with `$` prefix

## What is DynamicProperty?

`DynamicProperty` is a protocol in SwiftUI that allows property wrappers to participate in the view update cycle. This is the secret sauce that makes property wrappers like `@State` and `@ObservedObject` trigger view updates.

### How DynamicProperty Works

When a property wrapper conforms to `DynamicProperty`, SwiftUI does the following:

1. Tracks the property wrapper as part of the view's state
2. Calls the `update()` method before each view render
3. Automatically invalidates and re-renders the view when wrapped values change

Here's what the protocol looks like:

```swift
protocol DynamicProperty {
    mutating func update()
}
```

The `update()` method is called by SwiftUI before rendering the view body. You can implement custom logic here, but often you don't need to provide an implementation as the default behavior is sufficient.

## Creating a Custom Property Wrapper for SwiftUI

Now let's combine both concepts to create a property wrapper that makes SwiftUI views react to changes.

### Step 1: Basic Structure

```swift
@propertyWrapper
struct MyState<Value>: DynamicProperty {
    @State private var value: Value
    
    var wrappedValue: Value {
        get { value }
        nonmutating set { value = newValue }
    }
    
    init(wrappedValue: Value) {
        _value = State(wrappedValue: wrappedValue)
    }
}
```

### Step 2: Understanding the Components

**DynamicProperty conformance**
By conforming to `DynamicProperty`, we tell SwiftUI to track this wrapper as part of the view's state system.

**Internal @State property**
We use `@State` internally because it already knows how to trigger view updates. This is composition at work.

**nonmutating setter**
The `nonmutating` keyword is crucial. SwiftUI views are structs, which are value types. Normally, you can't mutate properties of a struct without marking the method as `mutating`. However, `@State` and similar wrappers use `nonmutating set` to allow mutations without requiring the entire view to be marked as `mutating`.

### Step 3: Using the Custom Property Wrapper

```swift
struct ContentView: View {
    @MyState var count = 0
    
    var body: some View {
        VStack(spacing: 20) {
            Text("Count: \(count)")
                .font(.largeTitle)
            
            Button("Increment") {
                count += 1
            }
        }
    }
}
```

When you tap the button, the count changes, and SwiftUI automatically re-renders the view. This happens because:

1. `MyState` conforms to `DynamicProperty`
2. The internal `@State` property publishes changes
3. SwiftUI detects the change and invalidates the view
4. The view body is called again with the updated value

## Advanced Example: Custom Property Wrapper with Binding

Let's create a more sophisticated wrapper that also provides a `Binding`:

```swift
@propertyWrapper
struct Validated<Value>: DynamicProperty {
    @State private var value: Value
    private let validator: (Value) -> Bool
    
    var wrappedValue: Value {
        get { value }
        nonmutating set {
            if validator(newValue) {
                value = newValue
            }
        }
    }
    
    var projectedValue: Binding<Value> {
        Binding(
            get: { value },
            set: { newValue in
                if validator(newValue) {
                    value = newValue
                }
            }
        )
    }
    
    init(wrappedValue: Value, validator: @escaping (Value) -> Bool) {
        self.validator = validator
        _value = State(wrappedValue: wrappedValue)
    }
}

// Usage
struct FormView: View {
    @Validated(validator: { $0.count >= 3 }) var username = ""
    
    var body: some View {
        VStack {
            TextField("Username (min 3 chars)", text: $username)
            Text("Username: \(username)")
        }
    }
}
```

## Alternative Approaches

You can also use `@StateObject` with `ObservableObject` for more complex state management:

```swift
@propertyWrapper
struct Reactive<Value>: DynamicProperty {
    @StateObject private var storage: Storage<Value>
    
    var wrappedValue: Value {
        get { storage.value }
        nonmutating set { storage.value = newValue }
    }
    
    init(wrappedValue: Value) {
        _storage = StateObject(wrappedValue: Storage(value: wrappedValue))
    }
    
    private class Storage<T>: ObservableObject {
        @Published var value: T
        
        init(value: T) {
            self.value = value
        }
    }
}
```

This approach is useful when you need more control over observation and publishing changes.

## Key Takeaways

1. **Property wrappers** encapsulate reusable property logic and are marked with `@propertyWrapper`

2. **DynamicProperty** is the bridge between your property wrapper and SwiftUI's update system

3. **Composition over reimplementation** - Use existing wrappers like `@State` internally rather than rebuilding from scratch

4. **nonmutating setters** allow property modification without requiring mutable view contexts

5. **Projected values** (accessed with `$`) provide additional functionality like bindings


## Conclusion

While SwiftUI's built-in property wrappers cover most use cases, knowing how to create your own gives you the flexibility to build exactly what your app needs.


