Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NSUserDefaults initWithSuiteName persisting after deleting app

I have an issue where if I store any data using [[NSUserDefaults alloc] initWithSuiteName:SUITE_NAME]] the data persists even after deleting the app. Is this supposed to happen?

like image 221
thisiscrazy4 Avatar asked Apr 21 '15 21:04

thisiscrazy4


People also ask

Is NSUserDefaults persistent?

Preferences stored in NSUserDefaults persist across reboots and relaunches of apps unless otherwise specified.

Where are NSUserDefaults stored?

All the contents saved by NSUserDefaults is saved inside a plist file that can be found under Library -> Preferences -> $AppBundleId.

Is NSUserDefaults secure?

Because NSUserDefaults stores all data in an unencrypted . plist file, a curious person could potentially view this data with minimal effort. That means that you should never store any type of sensitive data inside NSUserDefaults.

Is NSUserDefaults thread safe?

Thread SafetyThe UserDefaults class is thread-safe.


2 Answers

This is supposed to happen. This is in fact the purpose of initWithSuiteName, to share data between all apps in the app group. The docs say:

Use this method in scenarios such as:

  • When developing an app suite, to share preferences or other data among the apps

  • When developing an app extension, to share preferences or other data between the extension and its containing app

There is no way for an app to delete this, because when an app is deleted it is not notified. This is the same issue with storing items in the Keychain -- they persist beyond the life of the app. This can be a good or a bad thing depending on your app's needs.

One solution is to encrypt the appropriate parts of contents of the file and store the key in a shared keychain. For something like this, a random 256-bit AES symmetric key is perfect. Generally though, as long as the user has a passcode on the device, the filesystem is encrypted and items in the shared storage should be considered clean.

Another option is to use shared storage as a passthrough; we do this in our suite of apps. One app will put an encrypted file in shared storage, then call another app in our suite with the file URI and the encryption key. The receiving app will copy the file into its local storage, remove the shared file and then decrypt the local file.

like image 76
David S. Avatar answered Oct 08 '22 04:10

David S.


As others have mentioned, defaults stored in a shared suite can persist despite deletion of the app and there is no way of detecting app deletion and cleaning up these defaults. However, there is a way to deal with it in the case of somebody reinstalling the app (and you don't want the old defaults to be there).

To deal with this, you can simply save a bool to the standard user defaults on startup of the app. If the bool is not present when you start the app (as it is the first installation), then you can purge the shared suite defaults to make it start up as a fresh install. In this way, on a fresh install you'll have an empty shared defaults.

For example:

let defaults = NSUserDefaults.standardUserDefaults()
if !defaults.boolForKey("firstInstallComplete") {
    let sharedSuite = NSUserDefaults(suiteName: "com.example.app.shared")!

    // delete whatever keys you want
    sharedSuite.removeObjectForKey("example")
    sharedSuite.removeObjectForKey("another")
    ...
    sharedSuite.synchronize()

    defaults.setBool(true, forKey: "firstInstallComplete")
    defaults.synchronize()
}
like image 44
Ben Dodson Avatar answered Oct 08 '22 04:10

Ben Dodson