# 10 Step Guide: SwiftUI ObservableObject to Observable Macro Transition

In my last article, I talked about [how data flows in SwiftUI](https://namitgupta.com/5-essential-elements-to-understanding-data-flow-in-swiftui). Now, Apple has released something new in iOS 17 - the [Observation Framework](https://developer.apple.com/documentation/observation). This changes how SwiftUI works with data. In this article, we will look at how to use the new Observable Macro in your SwiftUI code.

## Step 1: Understand the Observable Macro

`Observable` Macro generates code automatically for you to observe data changes. Compared to the old `ObservableObject` protocol, this feature is more powerful as it tracks changes in optional and collection data types and enhances your app's performance by avoiding unnecessary updates.

## Step 2: Import the Observation Framework

Start by importing the new `Observation` framework. You'll then need to replace the `ObservableObject` with the `Observable` macro. For example, the class "MovieLibrary" was an `ObservableObject` will become an `Observable`:

```swift
// BEFORE
import SwiftUI

class MovieLibrary: ObservableObject {
    // ...
}

// AFTER
import SwiftUI
import Observation

@Observable class MovieLibrary {
    // ...
}
```

## Step 3: Remove the Published Wrapper

Before, you had to wrap observable properties with `Published`. But the Observable macro takes care of that. So, you can remove the `Published` wrapper. For instance:

```swift
// BEFORE
@Observable class MovieLibrary {
    @Published var movies: [Movie] = [Movie(), Movie(), Movie()]
}

// AFTER
@Observable class MovieLibrary {
    var movies: [Movie] = [Movie(), Movie(), Movie()]
}
```

## Step 4: Ignore Properties If Needed

What if you don't want to track certain properties? Just use the `ObservationIgnored` macro:

```swift
@Observable class MovieLibrary {
    @ObservationIgnored var somePropertyNotToTrack: Int = 0
    var movies: [Movie] = [Movie(), Movie(), Movie()]
}
```

## Step 5: Start Migration Gradually

SwiftUI allows you to change your code bit by bit. You can start by converting one data model to use the `Observable` macro and then move to others. But, remember that the way SwiftUI tracks changes might be slightly different now.

## Step 6: Replace StateObject with State

Once you've converted all data models to use the `Observable` macro, replace `StateObject` with `State`:

```swift
// BEFORE
@main
struct MovieApp: App {
    @StateObject private var movieLibrary = MovieLibrary()

    var body: some Scene {
        WindowGroup {
            MovieLibraryView()
                .environmentObject(movieLibrary)
        }
    }
}

// AFTER
@main
struct MovieApp: App {
    @State private var movieLibrary = MovieLibrary()

    var body: some Scene {
        WindowGroup {
            MovieLibraryView()
                .environment(movieLibrary)
        }
    }
}
```

## Step 7: Replace EnvironmentObject with Environment

Next, you should replace the `EnvironmentObject` property wrapper with `Environment`:

```swift
// BEFORE
struct MovieLibraryView: View {
    @EnvironmentObject var movieLibrary: MovieLibrary

    var body: some View {
        List(movieLibrary.movies) { movie in
            MovieView(movie: movie)
        }
    }
}

// AFTER
struct MovieLibraryView: View {
    @Environment(MovieLibrary.self) private var movieLibrary

    var body: some View {
        List(movieLibrary.movies) { movie in
            MovieView(movie: movie)
        }
    }
}
```

## Step 8: Remove the ObservedObject Wrapper

Now it's time to remove the `ObservedObject` property wrapper. This property wrapper isn’t needed when adopting Observation. That’s because SwiftUI automatically tracks any observable properties that a view’s `body` reads directly. For example:

```swift
// BEFORE
struct MovieView: View {
    @ObservedObject var movie: Movie
    @State private var isEditorPresented = false

    var body: some View {
        HStack {
            Text(movie.title)
            Spacer()
            Button("Edit") {
                isEditorPresented = true
            }
        }
        .sheet(isPresented: $isEditorPresented) {
            MovieEditView(movie: movie)
        }
    }
}

// AFTER
struct MovieView: View {
    var movie: Movie
    @State private var isEditorPresented = false

    var body: some View {
        HStack {
            Text(movie.title)
            Spacer()
            Button("Edit") {
                isEditorPresented = true
            }
        }
        .sheet(isPresented: $isEditorPresented) {
            MovieEditView(movie: movie)
        }
    }
}
```

## Step 9: Use the Bindable Wrapper

If your view needs a binding to an observable type, replace `ObservedObject` with the `Bindable` property wrapper:

```swift
// BEFORE
struct MovieEditView: View {
    @ObservedObject var movie: Movie
    @Environment(\.dismiss) private var dismiss

    var body: some View {
        VStack() {
            TextField("Title", text: $movie.title)
                .textFieldStyle(.roundedBorder)
                .onSubmit {
                    dismiss()
                }

            Button("Close") {
                dismiss()
            }
            .buttonStyle(.borderedProminent)
        }
        .padding()
    }
}

// AFTER
struct MovieEditView: View {
    @Bindable var movie: Movie
    @Environment(\.dismiss) private var dismiss

    var body: some View {
        VStack() {
            TextField("Title", text: $movie.title)
                .textFieldStyle(.roundedBorder)
                .onSubmit {
                    dismiss()
                }

            Button("Close") {
                dismiss()
            }
            .buttonStyle(.borderedProminent)
        }
        .padding()
    }
}
```

## Step 10: Congratulations - You've Migrated!

By following these steps, you've just migrated to the Observable macro in SwiftUI. Great job! You've enhanced your app's performance and can now track changes in your data more effectively.

*You may also like:* [*7 Key Strategies for Reducing Code Duplication in SwiftUI*](https://namitgupta.com/7-key-strategies-for-reducing-code-duplication-in-swiftui)  
  
I hope you enjoyed this article, and if you have any questions, comments, or feedback, then feel free to comment here or reach out via [**Twitter**](https://twitter.com/iamnamitg).

Thanks for reading!
