UserDefaults
is probably one of the most popular APIs on Apple Platforms. It is a highly-optimized key-value persisted store that is backed by a property list, and it is most commonly used for saving small pieces of data like user preferences. Despite its ease-of-use, there is one common anti-pattern I see developers use often.
In dozens of iOS projects over the years, I find that developers are prefixing key names with the app’s bundle identifier. For example, instead of naming a key "sounds-enabled"
it will be named "com.mycompany.MyApp.sounds-enabled"
. I am writing this post as a PSA to tell you that you do not need to do this!
On iOS, in your application’s user data sandbox you will find the backing plist for UserDefaults
at ~/Library/Preferences/com.mycompany.MyApp.plist
. On macOS, for a non-sanboxed app you will find the plist at the same path and for an app that is sandboxed you will find the plist at ~/Library/Containers/MyApp/Data/Library/Preferences/com.mycompany.MyApp.plist
.
As you can see, your instance of UserDefaults
is already namespaced by your app’s bundle identifier! Prefixing your keys is redundant. So please — do not prefix your key names with your app’s bundle identifier!
* * *
You might argue that prefixing key names is harmless, and that could be true sometimes. However, there are known issues with UserDefaults
key-value observing if key names have periods in the name — KVO does not work in that scenario. Furthermore, if you use debug tools (like FLEX) that allow you to inspect the values saved in UserDefaults
or if you manually open the plist (which is just XML) to examine it, it gets really cumbersome to search and read through if every single key is prefixed with the same ~30 characters.
Lastly, if you are convinced to drop the unnecessary prefixes, beware that you will need to write migration code to save your values from the old key to the new one, otherwise you will lose data.
Update 17 July 2023
A few folks on Mastodon have pointed out situations where prefixing might be warranted. Or rather, pointed out problematic scenarios to generally watch out for.
Greg Heo mentioned that you should carefully consider your key names if you are using UserDefaults
shared domains. Typically, this scenario would be sharing data between your main app and an extension — so hopefully you are not colliding with your own key names.
Matt Massicotte noted that some system frameworks store values in your app’s UserDefaults
. For example, AppKit and SwiftUI on macOS store state restoration data, most commonly window size and location. I had forgotten about this. However, I highly doubt you’ll have naming collisions. For example, here are a couple of keys for one of my apps: NSWindow Frame com_apple_SwiftUI_Settings_window
, com_apple_SwiftUI_Settings_selectedTabIndex
.
More importantly, Andy Ibanez warned that a third-party dependency might read and write to the same key name. That is very bad! If you are a library author, you should not be writing to UserDefaults.standard
. This is why UserDefaults.init(suiteName:)
exists — your library should initialize its own suite.
All of these are valid concerns. Still, I think for the majority of use cases, prefixing is not necessary.