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:
-
The "standard" UserDefaults usage pattern would store your SDK’s preferences inside the app’s preference file, which means collisions are possible.
-
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