Sharing NSUserDefaults between your app and a Today Extension on iOS 8

by: dermdaly

Today extensions are the new iOS 8 feature that allows you to put widgets on the Notification Screen. This post will show you how you can share data through NSUserDefaults.

This is a simple, but probably common use case. Your main app has a set of “things” it displays, and the user may want to display some of these “things” on the Notification screen, so the app allows you to specify this. It’s not unusual to store this meta-data in NSUserDefaults.

At WWDC we’ve been told that Today Extensions run in a separate process, so have their own sandbox. By default, there’s no mechanism for sharing. Of course the engineers at Apple have considered this, so here are the details.

Sharing of data is achieved through a new concept called “App Groups”. App Groups are allowed to share some data, including files, but it is worth noting that file access needs to be marshalled to avoid concurrent writes and so forth. This can be achieved through NSFileCoordination, but CoreData and NSUserDefaults handle this out of the box.

To read from the same set of NSUserDefaults:

  1. In your main app, select your project in the project navigator.
  2. Select your main app target and choose the capabilities tab.
  3. Switch on App Groups (this will communicate with the developer portal, as it is generating a set of entitlements, and relevant App Id and so forth).
  4. Create a new container. According to the help, it must start with “group.”, so give it a name like “”.
  5. Select your Today Extension target and repeat this process of switching on app groups. Don’t create a new one, rather select this newly created group to signify that the Today Extension is a member of the group.
  6. When reading or writing your NSUserDefaults in either your app or your extension, don’t access [NSUserDefaults standardUserDefaults]. Instead use [[NSUserDefaults alloc] initWithSuiteName:@""] Note: You must use the name of your group in as the suite name.

Now both your extension and your app will be accessing the same set of NSUserDefaults, so can share data.

Other tips:
If you’ve abstracted reading/writing of NSUserDefaults to a class, you can extract this into a Framework that both your app and Extension link to. Building Frameworks for Cocoa Touch is now pretty simple in XCode 6/iOS 8.

Don’t forget this still involves two separate processes. For example, my original abstracted class used a singleton pattern and cached some of the data in memory. This of course won’t work; two processes means two completely separate singletons which were blissfullly unaware when a process updated the file. I just had to alter properties to read from NSUserDefaults every time, rather than using an in-memory copy.

You May Also Like

We built a product in a lockdown

At the start of the lockdown, around March last year, I have to admit a case of the jitters. I was prospecting on five different projects. Some with existing clients, some with new clients. Our order book was good - but we always have to have an eye on up coming...

read more
The Rise of the Super App

The Rise of the Super App

Imagine being able to chat with your friend through instant messaging, then book dinner, a movie or a gig and pay for everything all from one single app. Thatโ€™s the power of a super app.  Mobile users worldwide have dedicated apps for specific tasks. This is not...

read more


  1. LinLin

    You said Instead use [[NSUserDefaults alloc] initWithSuiteName:@”group.mycompany.myapp”. May I know it is that one or

    • zourtney

      For me, it had to be the exact name used in Project -> Capabilities -> App Groups. Any attempt to further namespace it (by appending “.something”) simply didn’t work.

  2. jk9357

    If you have other data that you can’t store using NSUserDefaults (for example cell icons), you can use:

    NSURL *containerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@””];
    containerURL = [containerURL URLByAppendingPathComponent:[NSString stringWithFormat:@”nc-icon%ld.jpg”,indexPathRow]];
    UIImage *contents=[[UIImage alloc]initWithData:[NSData dataWithContentsOfURL:containerURL]];

  3. Jeeeyul

    Thanks for your writing!
    I wonder something about shared user defaults.

    Is there anyway to expose shared user defaults as a settings bundle rather then in app preferences?


    Hi, I am trying the exact solution you posted, and it worked well on simulators but not on my device(iPhone 5, iPad Air), do you have any suggestion on this?
    I made sure that my App Group ID was added to the entitilement on both targets, provisioning profiles also have App Group enabled. And I updated my device to iOS8 beta 2, am I missing anything here?

    • vivian

      Have you resolve the problem? I have the same question. could you tell me how to do…
      can’t get any data on device…but perfect on simulate…

      • vivian

        Done…I made a mistake

  5. Kirk Beitz

    your group name is
    but then in the NSUserDefaults initWithSuiteName, you say @”group.mycompanyname.myapp”

  6. Ive

    Hi. Nice Tutorials.

    However in my keyboard extension , i tried with App Group , including initWithSuitName in NSUserDefault . But It doesn’t work.

    App Group is successfully done in developer portal and XCode.

    I have to save Boolean Value in NSUserDefault.
    But I can’t load Boolean Value in extension.

    • devmario

      Are you fixed your problem?
      Your issue is same my issue.

    • devmario

      i fixed this issue.
      enable allow access at keyboard setting

      • vivian

        my project is today extension. there is no setting about access… How I can do ? worked well on simulators but not on my device(iPhone 5, iOS8)

  7. Roy

    Hi. Thanx for the sharing. I have an additional question. I found that I can add UIScrollView in the view of widget, but scrolling was not possible. Does anybody know how to enable scrolling in the view of widget?

  8. Roy

    Hi. Thanx for the sharing. I have an additional question. I found that I can add UIScrollView in the view of widget, but scrolling was not possible. Did you try enabling scrolling in the view of widget?

  9. dermdaly

    Thanks for all the comments and feedback. A couple of people pointed out I had a mismatch between the group name and the parameter passed to initWithSuiteName. This was a typo, and I’ve edited it accordingly.

  10. Max


    Just pointing out: it seems that NSUserDefaultsDidChangeNotification does not work with the shared defaults as of xcode6-beta6 and iOS-beta5.

    I tried for a long time and failed. If someone succeeds, please let me know ๐Ÿ™‚

  11. Ben Chatelain

    Your last paragraph calls out an important caveat about wrapping NSUserDefaults in a singleton. This will work provided you call -synchronize after values are modified in the app and then call -synchronize from inside the extension before trying to read values. Standing up a fresh instance using -initWithSuiteName: each time is essentially doing the same thing.

  12. Bernd R.

    I couldn’t get it to work that writing to NSUserDefaults from a Today Extension triggers NSUserDefaultsDidChangeNotification in your running App!?

  13. Tim Davies

    For those struggling to with getting Settings Bundle’s to target App-Group settings instead of the App Targets user defaults, all you need to do is add “ApplicationGroupContainerIdentifier” as a key to the Root.plist of your Settings Bundle and set its value as your App-Group identifier.

  14. Artem

    When I use iOS 7 NSUserDefaults initiated by ‘initWithSuiteName:’ return nil value for all keys. In iOS 8 works fine. What is wrong? Help me please!

  15. Lasse Bunk

    Thanks for posting this! Very helpful. ๐Ÿ™‚


Submit a Comment

Your email address will not be published. Required fields are marked *