Search code examples
swiftuiappstorage

Why does @AppStorage default value always reinitialize with UUID?


Once the app is started (first time), I want to assign the user a unique ID (not for tracking, and not for device ID, just a light-weight user ID to give the backend something to tie requests to).

I have this simple line of code in SwiftUI (App.swift):

@AppStorage("userId") var userId: String = UUID().uuidString

In the same class, I do this:

init() {
    print("User ID: \(userId)")
}

Every single time I run this, the UUID is a DIFFERENT one. Now, I know what the first response may be: this is due to the simulator and me crashing the app (by re-running it).

I have, however, tried the following, and received the same result (i.e. different UUID on every start):

  1. Run in simulator, drag app up, kill it that way. Nope.
  2. Background app, give it time, run other app, drag it up and kill it. Nope.
  3. Run the same on a real phone (via Xcode). Background it, kill it after some time. Nope.

This thread seems to be sure it's because of the development context, but how can I ever test this in development then? Background does NOT work for me?


Solution

  • isn't that the entire idea of the AppStorage utility, to take care of the "default" value for me

    Yes

    i.e., if nothing is set, it sets it with UUID().uuidString

    No. It doesn't set anything if nothing is set in UserDefaults. The AppStorage property wrapper only writes to UserDefaults if you call the property's setter. If you are calling its getter and nothing is set in UserDefaults, the getter will just return the default value you specified (UUID().uuidString) without writing anything. This is why the id is different every time.

    A simple solution is to do

    userId = userId
    

    when your app starts. in init or onAppear or otherwise.

    This first calls the getter, which returns the default value, and writes that to UserDefaults because the setter is called. When this is run again, the getter no longer returns the default value (which would have been different), because the key is set in UserDefaults.