UserDefaults is a great place to keep a small amount of data for your application. You can keep there some config but data can’t be big.
It’s perfect for some String or Int variable. It also can keep Arrays, Dictionaries, or Data. There isn’t any official information in the documentation about size limit but it isn’t recommended to use it as the main database because for example it’s loaded to memory when the app starts.
If you aren’t sure what data it inside UserDefaults you can get all data from it.
Let’s say you have an app that can receive push notifications and you want to know last time when push notification arrived at your app.
Instead of using a database, you can keep this information inside UserDefaults.
The first approach looks like:
// Inside notification extension
let userDefaults = UserDefaults()
userDefaults.set(Int(Date().timeIntervalSince1970), forKey: “LastPushNotification”)
print(userDefaults.integer(forKey: “LastPushNotification”))
Output
1595345104 // seconds since 1970, different in your case
// Main app
let userDefaults = UserDefaults()
let lastPushNotification = userDefaults.integer(forKey: “LastPushNotification”)
print(lastPushNotification)
Output
0
Why the output is 0? Because there isn’t value for this key and the default value is 0.
Now you don’t have any value inside the main app. Why? Because main and extension create their own instance of UserDefaults and they don’t have it by default.
To share it you need to create UderDefaults with parameter suiteName and set App Group Capability.
Open Navigator -> your app target -> Signing & Capabilities -> +Capability -> App Groups. Click + button at the bottom and add the group name starting with “group.” and click the refresh button at the bottom. Do the same for your extension.
Now change UserDefault constructor in both places, main app, and extension.
let userDefaults = UserDefaults(suiteName: “group.your.app.group.name”) <- you need to check it to your App Group name.
Now run extension and save the last push notification time. And rerun the main app and you’ll receive time from the extension.
Now you can share data using UserDefaults between the main app and extension.
Notice that instances with and without suiteName in constructors are different things.
You may see this kind of log:
Couldn’t read values in CFPrefsPlistSource<0x2823ff500> (Domain: your.app.bundle, User: kCFPreferencesAnyUser, ByHost: Yes, Container: (null), Contents Need Refresh: Yes): Using kCFPreferencesAnyUser with a container is only allowed for System Containers, detaching from cfprefsd
This warning can display all the time and it comes from some internal API and in theory, it shouldn’t display but it does. Apple developer claims we should ignore it. Maybe they’ll fix it in the future. I found this type of answer on Apple’s developer forum.