Steve M
Steve M

Reputation: 9784

Initialize optional @AppStorage property with non-nil value

I need an optional @AppStorage String property (for a NavigationLink selection, which required optional), so I declared

@AppStorage("navItemSelected") var navItemSelected: String?

I need it to start with a default value that's non-nil, so I tried:

@AppStorage("navItemSelected") var navItemSelected: String? = "default"

but that doesn't compile.

I also tried:

init() {
    if navItemSelected == nil { navItemSelected = "default" }
}

But this just overwrites the actual persisted value whenever the app starts.

Is there a way to start it with a default non-nil value and then have it persisted as normal?

Upvotes: 4

Views: 4800

Answers (3)

Kadie
Kadie

Reputation: 11

This hacking with swift article has an example of setting a default to a non-optional string value while using @AppStorage. This works for me with a boolean value as well.

struct ContentView: View {
    @AppStorage("username") var username: String = "Anonymous"

    var body: some View {
        VStack {
            Text("Welcome, \(username)!")

            Button("Log in") {
                username = "@twostraws"
            }
        }
    }
}

Upvotes: 0

Adam
Adam

Reputation: 5115

@AppStorage is a wrapper for UserDefaults, so you can simply register a default the old-fashioned way:

UserDefaults.standard.register(defaults: ["navItemSelected" : "default"])

You will need to call register(defaults:) before your view loads, so I’d recommend calling it in your App’s init or in application(_:didFinishLaunchingWithOptions:).

Upvotes: 2

Asperi
Asperi

Reputation: 257749

Here is a simple demo of possible approach based on inline Binding (follow-up of my comment above).

Tested with Xcode 13 / iOS 15

demo

struct DemoAppStoreNavigation: View {
    static let defaultNav = "default"
    @AppStorage("navItemSelected") var navItemSelected = Self.defaultNav

    var body: some View {
        NavigationView {
            Button("Go Next") {
                navItemSelected = "next"
            }.background(
                NavigationLink(isActive: Binding(
                    get: { navItemSelected != Self.defaultNav },
                    set: { _ in }
                ), destination: {
                    Button("Return") {
                        navItemSelected = Self.defaultNav
                    }
                    .onDisappear {
                        navItemSelected = Self.defaultNav   // << for the case of `<Back`
                    }
                }) { EmptyView() }
            )
        }
    }
}

Upvotes: 2

Related Questions