Should SDK developers use UserDefaults?

UserDefaults store app-related settings, and I am just worried that if an SDK also writes to the UserDefaults, that there could be potentially some key collisions between the host app and the SDK.

Is the concern just in my head or does it have merit?

There is no risk (of course, designers thought of it), as user defaults are stored in different domains, and there is one for each app, another for system.

Question is not only specific SDK and app, but between any apps

More details here: https://developer.apple.com/documentation/foundation/userdefaults

To integrate settings from different sources, the defaults system organizes them into domains. An app defines its own custom settings, but the system defines settings that apply to all apps.

Don't forget to close the thread if that answers your question.

Hey there. You guys are generally trending in the right direction, but I think some points could use some clarification and additional information.

  1. Every app on the system has its own preferences source, accessed through +standardUserDefaults. There's no opportunity for different apps to encounter key collisions between them, because the data is all separated by app sandbox containerization.
  2. System frameworks can and do read and write their own preferences, but there are several ways this could happen: A) It writes directly into +standardUserDefaults—the "app-owned" preferences—which technically could collide with the app, but avoids it via convention (typically prefixes). B) It reads and writes into a custom domain—usually named after the framework—within the app's own sandbox, separated from every other app. C) It reads from a custom domain—again named after the framework—from outside the sandbox; this is usually for global settings as modified in Settings and typically aren't writable from the app.
  3. Preferences can also be stored in app group domains, which are shared between apps within the app group. These are accessed via the "initWithSuiteName:" API, but this is not the only use for that API. Not only can frameworks use this as mentioned above, but an app can even invent its own arbitrary domains to store preferences in besides +standardUserDefaults if it chooses to. These will also be stored within the app's sandbox container.

So to answer your original question concisely: yes, while it's technically possible for a framework to create a key collision with an app's own preferences, this is unlikely due to the prefixing conventions.

UserDefaults store app-related settings, and I am just worried that if an SDK also writes to the UserDefaults, there could be potentially some key collisions between the host app and the SDK.

Is the concern just in my head or does it have merit?

Yes, this concern has merit. More specifically:

  1. The "standard" UserDefaults usage pattern would store your SDK’s preferences inside the app’s preference file, which means collisions are possible.

  2. You could manipulate UserDefaults to store them in a different file; however, depending on how you do that, you risk creating new collisions (when multiple apps use the same SDK) and/or additional complication/confusion, as the app’s preference data no longer exists in a single location.

In most cases, I think #2 creates more problems than it solves, so the solution is to manage your UserDefaults usage to avoid collisions. That means:

  • Use a key naming convention like reverse DNS (com.mysdk.stuff) that discourages collisions.

  • Consolidate your preferences to minimize the total number of top-level keyed entries. For example, storing a dictionary with 10 entries using one top-level key instead of storing 10 individual entries and keys.

  • Ideally, document exactly what key names you’re using so that developers know what they have to avoid.

Note that all of these points aren't simply about avoiding collision, but can also make your SDK more "friendly" to the developer. For example, the second point means that you can have a high entry count while keeping the app’s defaults file easy to interpret.

That also leads to my second point, which is to be sure you're using UserDefaults for what it was designed for ("app preferences"), not as a quasi-database. I've seen many apps that use UserDefaults for "general storage" which works well enough that you can ship an app and badly enough that it'll eventually break. A few recommendations on that point:

  • If deleting your defaults entries would be a significant "problem" for the user, then that's "data", not "preferences". Don't use UserDefaults to store data.

  • Don't store user names, passwords, or other security-related data in UserDefaults. That's what the keychain is for.

  • If you particularly "like" the plist format[1] (for example, because it makes it easy to view your data in external apps), then you can use PropertyListSerialization to easily read/write plist-formatted data to your own files. This makes it easy to have the same API "style" as UserDefaults with a file your app can directly manage.

Related to that last point, one other issue SDK vendors need to be aware of is the risk of UserDefaults data loss, caused by data protection issues. This forum post has a detailed rundown of what's involved, but the short summary is that there's a relatively common app bug which typically presents as "my app’s preferences vanished for no reason". There's no way for your SDK to prevent the problem (it's an app-level bug), but using the keychain or your own file means that you can prevent the bug from affecting your code.

There is no risk (of course, designers thought of it), as user defaults are stored in different domains, and there is one for each app, another for the system.

UserDefault domains are unrelated to this issue.

[1] I do, having helped more than one CoreData developer whose app would have been much better off just using a plist™.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Should SDK developers use UserDefaults?
 
 
Q