Data persistence using AppStorage and SceneStorage in SwiftUI iOS 24.05.2021

SwiftUI provides two approaches for storing small amount of data. It's a convenient way to store user's settings (@AppStorage) or value of text field between restarts (@SceneStorage).

AppStorage

The @AppStorage property wrapper can store data that is accessible throughout the entire app.

AppStorage uses UserDefaults as it backend and can store default user preferences (language preferences, color theme, etc).

To work properly @AppStorage requires a string as a key for inner storage

@AppStorage("theme") var theme: String = "bright"

SceneStorage

Alongside AppStorage, SwiftUI also offers a @SceneStorage attribute that works the same as @AppStorage, except that the persisted storage is limited to a scene instead of being app-wide.

@SceneStorage("about") var about: String = ""

Next, we can use it in conjunction with a TextEditor as follows

var body: some View {
    TextEditor(text: $about).padding()
}

This will ensure that any text entered into the text field is stored within the scene between app restarts.

Storing custom type

The @AppStorage and @SceneStorage can store only primitive types like Bool, Int, Double, String, URL and Data. All other types must be encoded in Data object and conforms to the Codable protocol.

Consider the following struct

struct Movie: Codable {
    var title: String
    var year: Int
}

var cinema = Movie(title: "The Godfather", year: 1972)

The following example uses a JSON encoder to encode cinema instance and store it using the @AppStorage.

@AppStorage("cinema") var cinemaStore: Data = Data()

let encoder = JSONEncoder()

if let data = try? encoder.encode(cinema) {
    cinemaStore = data
}

To retrieve the data from storage use following snippet

let decoder = JSONDecoder()

if let movie = try? decoder.decode(Movie.self, from: cinemaStore) {
    cinema = movie
}