90

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?

1
  • 7
    if you want to share resources between the extension and the app, the best way is to create an App Group and use the shared UserDefault (by -suiteName:) or the default FileManager (by -forSecurityApplicationGroupIdentifier:) only – you may not need the standard user-defaults or file-manager any longer (but if you need to be sure you want isolate data from the extension, you still can use those sandboxes).
    – holex
    Commented Aug 10, 2017 at 8:15

6 Answers 6

98

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")
3
  • 10
    This step is HIGHLY important.
    – P. Ent
    Commented Nov 19, 2020 at 15:32
  • Can we add any name to the group's identifier? Commented Dec 6, 2021 at 16:48
  • Thanks Tai Le. I was stuck on this. @user4150758 We have to set suiteName same as the App Groups name. otherwise it wan't work Commented Mar 8, 2022 at 13:38
91

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.

6
  • Apologies I assumed that as I was using ‘initSuiteName:’ that it would already give the impression I was using an App group. Which I am. Updated OQ to clarify this. Thanks
    – RyanTCB
    Commented Aug 10, 2017 at 8:26
  • So what is the issue that you are facing?
    – PGDev
    Commented Aug 10, 2017 at 8:28
  • 1
    I’m current persisting same data to both standard & suiteName constructors. Should I just drop standard() and use suiteName.
    – RyanTCB
    Commented Aug 10, 2017 at 8:32
  • 2
    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.
    – PGDev
    Commented Aug 10, 2017 at 8:34
  • (shouldn't the references to "host app" in this answer actually refer to the "container app"?)
    – benc
    Commented Aug 14, 2023 at 9:19
48

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")
    ...
}
2
  • 10
    You don't need to call synchroniz Commented Jun 21, 2019 at 13:51
  • 1
    This does not actually answer the question which one to use. If you do what you have written wont work if data was saved from host application using UserDefaults.standard(). Commented Aug 8, 2019 at 11:14
14

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)

5
  • It was so simple and i waste an hour. Thanks for pointing that out Commented Mar 10, 2020 at 19:19
  • Meh I wish I had read this post before wasting 3 hours... I had my extension group only on profile...
    – mrj
    Commented Mar 11, 2021 at 17:12
  • 1
    @Rahul Chhetri Not sure I see where this would be added to a Debug only configuration. I don't see where App Groups can be assigned to a configuration. Please clarify
    – JeffB6688
    Commented Feb 8, 2022 at 0:15
  • 3
    @JeffB6688 Okay I was confused by this initially. But as I was typing my original thoughts I discovered this. If you click on your project where the General, Signing & capabilities etc are. Select Signing & Capabilities, underneath that, there is "All, Debug, Release". This is what Rahul means by 'adding the app group to the debug and release'
    – Mark
    Commented Feb 11, 2022 at 23:44
  • Capabilities and Entitlements are sometimes managed by Xcode differently between debug and release, so this has probably happened to a lot of us.
    – benc
    Commented Aug 14, 2023 at 9:23
1

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

1

Wasted a lot of time, and the problem was in adding of app groups only for release configuration, and of course while testing of debug configuration - I couldn't access to shared data between app extension and container app. So, be sure u adding app groups to both configurations - release and debug.

enter image description here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.