Search code examples
iosswiftios-app-group

Why doesn't NSUserDefaults work between my app & share extension?


I have an iOS app with a share extension. I am trying to share data between them using NSUserDefaults and App Groups but, while I can write into the NSUD object, read it, and synchronize() without error, reading in the extension always results in nil.

I have an app group, the literal string "group.net.foo.bar" for which both the app & extension have configured under Capabilities -> App Groups. This string is in a constants struct in my app:

struct Forum {
    static let APP_GROUP = "group.net.foo.bar"
    static let AUTH_KEY = "AUTH_KEY"
}

In the main app I create a UserDefaults object and write to it:

fileprivate lazy var userDefaults: UserDefaults = {
    let defaults = UserDefaults()
    defaults.addSuite(named: Forum.APP_GROUP)
    return defaults
}()

// later
userDefaults.set(apiKey, forKey: Forum.AUTH_KEY)
userDefaults.synchronize()

Creating a new NSUD object after that synchronize() and retrieving the AUTH_KEY works. In the extension, I create an NSUD and try to retrieve the value, to no avail:

private lazy var userDefaults: UserDefaults = {
    let defaults = UserDefaults()
    defaults.addSuite(named: Forum.APP_GROUP)
    return defaults
}()

// later
private func getApiKey() -> String? {
    return userDefaults.string(forKey: Forum.AUTH_KEY)
}
// returns nil

In all of my reading of the Apple docs and depressingly-similar questions here on Stack Overflow I can't divine what I've done incorrectly.

Xcode Version 8.0 (8A218a), also tested with Xcode 8.1 Beta 2. Same behavior on simulator andy my iPhone 6s running iOS 10.


Solution

  • Not sure if defaults.addSuite(named: ...) does the same as UserDefaults(suiteName: ...). In my app I use appGroups this way and it works as expected:

    // write
    if let userDefaults = UserDefaults(suiteName: appGroupName) {
        userDefaults.set("---" as AnyObject, forKey: "distance")
        userDefaults.set("---" as AnyObject, forKey: "altitude")
        ...
        userDefaults.synchronize()
    }
    
    // read
    if let userDefaults = UserDefaults(suiteName: appGroupName) {
        self.distanceLabel.text = userDefaults.string(forKey: "distance")
        self.altitudeLabel.text = userDefaults.string(forKey: "altitude")
    }