# Property Wrappers

Because SwiftUI is declarative, the way we write the logic in our apps is completely different from how we would do it in UIKit. Let’s take a look at the following code that increments the value inside of a `Text` by 1 every time we click on a button:

```swift
struct ContentView: View {
    var count: Int = 0

    var body: some View {
        VStack {
            Text("Count: \(count)")

            Button {
                count += 1
            } label: {
                Text("Add")
            }
        }
    }
}
```

The above code will give us an error for the line containing `count += 1` indicating that ‘self’ is immutable. Why? That’s because we are using a struct. When we change the value of a property inside of a struct, the entire struct changes. If that’s the case, then how do we keep the struct object alive while being able to change the value of its properties? We use **property wrappers**.

### Using @State

To make the above code work, we can add the `@State` property wrapper to the `count` property. Because this object creates and owns this property, we should mark it as `private` for good practice:

```swift
struct ContentView: View {
    @State private var count: Int = 0

    var body: some View {
        VStack {
            Text("Count: \(count)")

            Button {
                count += 1
            } label: {
                Text("Add")
            }
        }
    }
}
```

The powerful thing about using these property wrappers is that SwiftUI automatically updates the views for us. When we incremented the value of `count`, the `Text` view using this property gets updated automatically.

### Two Way Binding

Now, let’s change things up and use a String with a `TextField`:

```swift
struct ContentView: View {
    @State private var name: String = "Vin"

    var body: some View {
        VStack {
            Text("Hello \(name)")

            TextField("Change Me", text: name)
        }
    }
}
```

If we try to run the above code, it will not work. That’s because the `name` variable that we pass into the `TextField` is a `String` and **NOT** `Binding<String>`. What does this “binding” mean? Let’s think about the difference between a `Text` and a `TextField`. A `Text` only reads the value that we pass in whereas a `TextField` reads **AND** writes a value. In this case, we must add a `$` to perform a two-way binding (in other words, a read and a write):

```swift
TextField("Change Me", text: name) // Incorrect
TextField("Change Me", text: $name) // Correct
```

### Reference Types

You may have noticed that we only used value types in the examples above. That’s because `@State` only works for value types such as structs, strings, ints, etc. However, there are times when we want to pass one reference around to multiple views. In this case, we want to use a *reference type*.

Consider the following code:

```swift
class User {
    var firstName: String = "Vin"
    var lastName: String = "Bui"
}

struct ContentView: View {
    @State private var user = User()

    var body: some View {
        VStack {
            Text("Hello \(user.firstName) \(user.lastName)")

            TextField("First Name", text: $user.firstName)
            TextField("Last Name", text: $user.lastName)
        }
    }
}
```

If we change the values inside of the text fields, the `Text` view will not be updated properly. One way to fix this is to change the `User` class to a struct. However, we want to keep it as a reference type.

When dealing with reference types, we must use a different property wrapper: `@StateObject`. To properly use this property wrapper, we must do the following (iOS 16 and below):

1. Conform our class to the `ObservableObject` protocol.
2. Mark the properties we want to observe with `@Published`.
3. Use `@StateObject` on our reference type property.

```swift
class User: ObservableObject {
    @Published var firstName: String = "Vin"
    @Published var lastName: String = "Bui"
}

struct ContentView: View {
    @StateObject private var user = User()

    var body: some View {
        VStack {
            Text("Hello \(user.firstName) \(user.lastName)")

            TextField("First Name", text: $user.firstName)
            TextField("Last Name", text: $user.lastName)
        }
    }
}
```

You may be wondering, “Why does `@State` work for structs but not classes?” When we use `@State` SwiftUI observes the entire value. When we change the property of a struct, the entire value changes since structs are value types. On the other hand, when we change the property of a class, the entire object does not change and a new copy is not created like it does with structs.

### Property Wrappers Cheat Sheet

The above property wrappers that we used only works if the view creates and owns the property. However, properties are often shared among views. If one child view changes a property, we also want to update it in the parent view. There are also different ways of sharing properties: (1) either directly (1-on-1) from a parent to child or (2) shared among every view through the environment.

Below is a list of some of the most common property wrappers and when we would use them.

#### @State

* The view itself **creates and owns** the instance we want to wrap.
* Property being wrapped is a **value type** (such as struct or enum).
* Mark as `private` for best practice. No external source should modify `@State` properties.
* Use `$` for a **two-way binding** to the property (read and write).

#### @StateObject

* Similar to `@State` but used on an `ObservableObject` (reference types).
* Changes to `@Published` properties are notified.
* The view itself creates and owns the instance.

#### @Binding

* `@State` Creates → `@Binding` Receives.
* Read and write to a property that's **owned by a parent view.**
* Property being wrapped is a **value type** (such as struct or enum).
* Use `$` for a t**wo-way binding** to the property (read and write).

#### @ObservedObject

* `@StateObject` Creates → `@ObservedObject` Receives.
* Similar to `@Binding` but used on an `ObservableObject` (reference types).
* Changes to `@Published` properties are notified.
* The view itself **DOES NOT create or own** the instance.

#### @EnvironmentObject

* Similar to `@ObservedObject` but **shared to MULTIPLE views**.
* The view itself **DOES NOT create or own** the instance.

### Flow Chart

*Where does the data come from?*

* Owned
  * Immutable Value? **Regular Property**
  * Mutable Value? **@State**
  * ObservableObject? **@StateObject**
* Parent
  * Immutable Value? **Regular Property**
  * Mutable Value? **@Binding**
  * ObservableObject? **@ObservedObject**
* Environment *(@Environment is to @EnvironmentObject → @State is to @StateObject)*
  * EnvironmentalValues, keyPath? **@Environment**
  * ObservableObject? **@EnvironmentObject**
* Saved on Disk
  * UserDefaults?
    * Whole app? **@AppStorage**
    * Single scene (for MacOS)? **@SceneStorage**
  * CoreData? **@FetchRequest**

### iOS 17 Onwards

Starting with iOS 17, we longer need to mark our class properties with `@Published` and conform our class to `ObservableObject`. All we have to do is add the `@Observable` property wrapper to our class. Additionally, we can just simply use `@State` on the class object.

Below is an iOS 17 version of the code we used earlier:

```swift
@Observable
class User {
    var firstName: String = "Vin"
    var lastName: String = "Bui"
}

struct ContentView: View {
    @State private var user = User()

    var body: some View {
        VStack {
            Text("Hello \(user.firstName) \(user.lastName)")

            TextField("First Name", text: $user.firstName)
            TextField("Last Name", text: $user.lastName)
        }
    }
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ios-course.cornellappdev.com/resources/textbook/swiftui/property-wrappers.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
