13

I have recently been building an app using [NSUserDefaults standartdUserDefaults] to store locally various information (regarding the session, user preferences, etc).

Now I am exporting a subpart of my project as an iOS framework (the goal is to make a SDK).

I am generating a MyKit.framework and MyKit.bundle to be imported in third party apps (the bundle contains Storyboards, Localizable.strings and .xcassets).

For the moment, I made sure that resources used by MyKit.framework are loaded from the MyKit.bundle scope and not the [NSBundle mainBundle] to avoid collisions with resources from the third party app.

Now, NSUserDefault can also leads to collisions if some keys are shared between the framework and the target apps.

Is - initWithSuiteName: the appropriate work around? Can I give a scope to NSUserDefaults ? Should I create a wrapper to access a custom NSUserDefaults domain ?

rmaddy
  • 314,917
  • 42
  • 532
  • 579
Romain Dorange
  • 831
  • 1
  • 10
  • 23
  • 4
    Why not use `NSUserDefaults standardUserDefaults`? Just be sure all of your keys look something like: `@"com.mydomain.frameworkname.keyname"`. No collisions will happen with that. – rmaddy May 07 '15 at 00:04
  • 1
    I believe initWithSuite is primarily designed when you want to share defaults within an AppGroup. – JamesSugrue May 07 '15 at 01:42
  • @maddy But where would you get your initial values? should the hosting app (building against your framework-SDK contain a resource in favour of your SDK? Isn't that plain-ugly? – Motti Shneor Jan 13 '19 at 08:52

1 Answers1

0

I'm working on the same problem myself.

My current observation is, since NSUserDefaults standardDefault contain a hierarchy of objects (like a .plist) you can put all your SDK's default key/values inside some "Dictionary" entry, (e.g. named after your SDK's domain - "com.mydomain.frameworkname"). That will box your items and set them apart from the app's own values.

There is a downside here - that KVO will only work for top-level key/value changes, so you won't be able to "register" for default-value-changes done directly in the NSUserDefaults.

Then, there's the part of "first time" loading of "factory default values" for the SDK, into the NSUserDefaults standardDefaults. For that, there is a standard behaviour and API, called "registerDefaults".

You can have some .plist resource in your SDK's bundle, called "factoryDefaults.plist" and then, in the initialisation of your SDK, you'll do something like this:

NSString *path = [[NSBundle bundleForClass:[self class]] pathForResource:@"factoryDefaults" ofType:@"plist"];
NSDictionary* factorySettings = [NSDictionary dictionaryWithContentsOfFile:path];
[[NSUserDefaults standardDefaults] registerDefaults:factorySettings];
[[NSUserDefaults standardDefaults] synchronize];

Then you can continue working with your default values, using standard user-defaults APIs, you can update them as needed, and still keep your hosting app's defaults kind-of-clean.

It is possible to hide the nuisance of digging into your SDK's single entry in NSUserDefaults standardDefaults, in a class that will kind-of override NSUserDefaults functions, and will access the SDK's entry instead of the top-level standardDefaults.

Word of caution: I'm only doing this now - can't yet report of success. So I will be thankful for any critic and recommendations, and you're welcome to try this method.

Motti Shneor
  • 2,095
  • 1
  • 18
  • 24