Core Data: Sharing Data between Apps and their Widgets

iNVASIVECODE
[cocoa gurus]
Published in
5 min readJan 29, 2015

--

An iOS SDK Tutorial

App Extensions, introduced with iOS 8, significantly increase our iOS App’s customizable functionality and extended content. App Extensions allow developers to project quick access to their app.

A Widget or a Today Extension, a particular type of App Extension, provides a quick update to users or lets them perform a simple task in their Notification Center’s today view. Widgets are powerful, but they raise an inherent problem: Sharing data between your App and its Widget. This problem is compounded because, by default, since their security domains are different, an App and its extension cannot access the same data.

In order to solve this problem we need to create an App Group.

CREATE AN APP GROUP

An App Group provides a shared bundle that can be used by the app and its extensions as a shared container in which we can store data.

The next following steps show you how to setup an App Group.

Step 1. Create the App Group in the Apple Developer Portal. An App Group ID always starts with the word group like group.com.yourdomain.YourAwesomeGroup.

Step 2. Create an App ID (if you don’t have one) for your App and enable App Groups.

Step 3. Assign the App Group you created in step 1 to your App ID.

Step 4. Repeat steps 2 and 3 for your App Extension.

Step 5. Create (or update if you already have one) a development provisioning profile for your App, so you can enable the needed entitlements.

Step 6. In the Xcode project of your App, select the Target for your App and go to the Capabilities tab. There, enable App Groups. Do the same in the Target of your App Extension.

Now, your app and its extension are ready to share the container, so it’s time to put the data in it.

PUT YOUR DATABASE IN THE SHARED CONTAINER

When you create a new Xcode project and select the Core Data checkbox, Xcode automatically generates some boilerplate methods in the App Delegate. This code is used at runtime to generate the Core Data stack of your App.

One of the boilerplate methods is the following one:

Objective-C

- (NSURL *)applicationDocumentsDirectory
{
// The directory the application uses to store the Core Data store file. This code uses a directory named "com.yourdomain.YourAwesomeApp" in the application's documents directory.

return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}

Swift

lazy var applicationDocumentsDirectory: NSURL = {
// The directory the application uses to store the Core Data store file. This code uses a directory named "com.yourdomain.YourAwesomeApp" in the application's documents Application Support directory.
let urls = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
return urls[urls.count-1] as NSURL
}()

This method simply returns the URL of the Documents directory in the App bundle.

We need to modify this method to point to the Shared Bundle, using the identifier of the App Group we recently created. Here, the new implementation:

Objective-C

- (NSURL *)applicationDocumentsDirectory
{
return [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.com.yourdomain.YourAwesomeGroup"];
}

Swift

lazy var applicationDocumentsDirectory: NSURL? = {
lazy var applicationDocumentsDirectory: NSURL? = {
return NSFileManager.defaultManager().containerURLForSecurityApplicationGroupIdentifier("group.com.yourdomain.YourAwesomeGroup") ?? nil
}()

If you are just starting a new App, that’s all you need to do.

Instead, if you already have an App in the AppStore and you are now adding a Widget, you need some additional work. Since your users might have already an Sqlite file in the Documents directory of your App bundle, you must migrate the Sqlite file to the new shared bundle. You need to perform this migration at the first launch of the App update.

USE CORE DATA IN YOUR APP EXTENSION

We need to access the shared Sqlite from the App Extension. Unfortunately, the templates provided by Xcode to create a new target for an App Extension do not provide a Core Data checkbox. So, some manual work is involved, this time. This process, nevertheless, is a great opportunity to increase your understanding of Core Data . I recommend taking a look at the Core Data methods in your App Delegate and moving them into a new class. In this way, the App and its extension will share the same source code. I’ll leave this exercise to you.

SHARE OTHER DATA

A good reason to use Core Data in the shared container is that Core Data will handle synchronization of the data accesses, avoiding data corruption.

However, Core Data isn’t always the right choice.

For example, you might want to save just few preferences of your App. You can save this type of information using the NSUserDefaults. To access the user defaults, you usually use the class method +standardUserDefaults. Since we have to access the shared container, we need to use a different initializer and pass the App Group identifier to it:

Objective-C

// Create and share access to an NSUserDefaults object.
NSUserDefaults *sharedDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.com.yourdomain.YourAwesomeGroup"];

// Use the shared defaults object to update your parameters.
[sharedDefaults setObject:anObject forKey:@"anObjectKey"];

Swift

let sharedDefaults = NSUserDefaults(suiteName: "group.com.yourdomain.YourAwesomeGroup")
sharedDefaults?.setObject(anObject, forKey: "anObjectKey")

CONCLUSION

In this iOS 8 Developer Tutorial, we setup an App Group and used it to share a container between an App and its Today extension. This method, which is essential for secure functionality, applies to any type of App extension.

Keep coding and making awesome apps.

Vicente

Vicente Vicens is an iOS and OS X developer dedicated exclusively to the Apple platforms since 2007. He has attended the WWDC every year since then. He previously worked for a chemical company wherein he designed their ERP, implementing quality systems and databases for tinting machines from scratch. The first computer he bought with the money earned with his first job was an Apple IIc, and he still has it.

--

--

iNVASIVECODE
[cocoa gurus]

iOS consulting and training. Expertise include: machine vision, pattern-recognition, biometrics, and loT.