Sharing UserDefaults between extensions

SwiftIos App-ExtensionToday ExtensionUserdefaultsIos App-Group

Swift Problem Overview


Creating a Today widget and I am using UserDefaults(suiteName:) to persist some data. In the main application I am using UserDefaults.standard(). This can't be read (or can it?) by the extension which is why I use the suiteName: constructor.

Data that user persist to UserDefaults.standard() in the main app needs to be available in the extension.

At this time I am persisting to both so that the values can be shared

 UserDefaults.standard().set:...forKey:...
 UserDefaults(suiteName:...)().set:...forKey:...
 ...

Question is should I drop UserDefaults.standard() all together and just use UserDefaults(suiteName:) in my application, or is this bad practice and if so why?

Edit: I am using an App group container. For clarification I am asking should I just replace standard() with suiteName: throughout my project?

Swift Solutions


Solution 1 - Swift

You cannot use UserDefaults.standard to share data between a host app and its app extension. You instead have to create a shared container with UserDefaults(suiteName:) to share data.

> Even though an app extension bundle is nested within its containing > app’s bundle, the running app extension and containing app have no > direct access to each other’s containers. > > To enable data sharing, use Xcode or the Developer portal to enable > app groups for the containing app and its contained app extensions. > Next, register the app group in the portal and specify the app group > to use in the containing app. > > After you enable app groups, an app extension and its containing app > can both use the NSUserDefaults API to share access to user > preferences. To enable this sharing, use the initWithSuiteName: method > to instantiate a new NSUserDefaults object, passing in the identifier > of the shared group.

For more, refer to: https://developer.apple.com/library/content/documentation/General/Conceptual/ExtensibilityPG/ExtensionScenarios.html#//apple_ref/doc/uid/TP40014214-CH21-SW1

How to use App Groups: https://github.com/pgpt10/Today-Widget

Standard or SuiteName?

Use standard one for data that is only for Host App. Use suiteName for data that you want to share between Extension and Host App. Just don't persist the same data in both of them. Avoid data redundancy. Use both of them according to the context.

Solution 2 - Swift

Make sure App Groups is enabled for ALL OF YOUR TARGETS (your app and extensions targets) in the Capabilities tab

enter image description here

And then use the group's identifier above as suite name when create UserDefaults:

let userDefaults = UserDefaults(suiteName: "group.com.YourCompany.YourApp")

Solution 3 - Swift

A simple example where I create a shared bundle:

if let userDefaults = UserDefaults(suiteName: "group.your.bundle.here") {
    userDefaults.set("test 1" as AnyObject, forKey: "key1")
    userDefaults.set("test 2" as AnyObject, forKey: "key2")
    userDefaults.synchronize()
}

This is how you can read it later:

if let userDefaults = UserDefaults(suiteName: "group.your.bundle.here") {
    let value1 = userDefaults.string(forKey: "key1")
    let value2 = userDefaults.string(forKey: "key2")
    ...
}

Solution 4 - Swift

Also make sure you add App Groups to the correct Configuration (Debug, Release). If you add App Groups in Debug for your application target and try to use it in Release config for your extension, then it wont work.

If you add in Debug config (for app target), then use it in debug config (for extension target)

Solution 5 - Swift

PGDev: augmentation:

you can't avoid redundancy when dragging Settings (preferences) https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/UserDefaults/Preferences/Preferences.html to an extension: they are contained in the app private bundle and have to be replicated into suitenamed bundle to become available to an app extension

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRyanTCBView Question on Stackoverflow
Solution 1 - SwiftPGDevView Answer on Stackoverflow
Solution 2 - SwiftTai LeView Answer on Stackoverflow
Solution 3 - SwiftoskarkoView Answer on Stackoverflow
Solution 4 - SwiftRahul ChhetriView Answer on Stackoverflow
Solution 5 - SwiftAnton TropashkoView Answer on Stackoverflow