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

Written by dermdaly on June 12th, 2014

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.

Comments (24)

LinLin says:

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

zourtney says:

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.

jk9357 says:

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]];

Jeeeyul says:

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 says:

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 says:

Done…I made a mistake

Kirk Beitz says:

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

Ive says:

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 says:

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

devmario says:

i fixed this issue.
enable allow access at keyboard setting

vivian says:

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)

Roy says:

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?

Roy says:

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?

mm dermdaly says:

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.

Max says:


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 🙂

devmario says:

this example is not working at custom keyboard extension.
please check this source

[…] Sharing NSUserDefaults between your app and a Today Extension on iOS8 […]

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.

Bernd R. says:

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

Tim Davies says:

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.

Artem says:

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!

Because of this post, I updated my NSUserDefaults wrapper to include suites. Thanks for the information!

Comment on this post

By continuing to use the site, you agree to the use of cookies. more information

The cookie settings on this website are set to "allow cookies" to give you the best browsing experience possible. If you continue to use this website without changing your cookie settings or you click "Accept" below then you are consenting to this.