8

I am confused about the search list feature in NSUserDefaults. The class reference says about the standardUserDefaults class method that it sets up a standard search list consisting of five domains. The docs for that method also imply that this search list can be changed (boldness added by me):

Subsequent modifications to the standard search list remain in effect even when this method is invoked again—the search list is guaranteed to be standard only the first time this method is invoked.

Let's also look at the docs for init:

Return Value: An initialized NSUserDefaults object whose argument and registration domains are already set up.

Discussion: This method does not put anything in the search list.

In my understanding this is a contradiction: Either the search list is empty, or it contains entries for the argument and registration domains.

Anyway, I did a bit of experimentation:

NSUserDefaults* standardUserDefaults = [NSUserDefaults standardUserDefaults];
// We get nil, which is expected
NSLog(@"test 1: expecting nil, getting %@", [standardUserDefaults objectForKey:@"foo"]);
NSDictionary* registrationDomainDefaults = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:42] forKey:@"foo"];
[standardUserDefaults registerDefaults:registrationDomainDefaults];
// We get 42, which is expected
NSLog(@"test 2: expecting 42, getting %@", [standardUserDefaults objectForKey:@"foo"]);
[standardUserDefaults removeSuiteNamed:NSRegistrationDomain];
[standardUserDefaults removeVolatileDomainForName:NSRegistrationDomain];
// Here we get 42!
NSLog(@"test 3: expecting nil, getting %@", [standardUserDefaults objectForKey:@"foo"]);

NSUserDefaults* myUserDefaults = [[NSUserDefaults alloc] init];
// Here we also get 42!
NSLog(@"test 4: expecting nil, getting %@", [myUserDefaults objectForKey:@"foo"]);
[myUserDefaults removeSuiteNamed:NSRegistrationDomain];
[myUserDefaults removeVolatileDomainForName:NSRegistrationDomain];
// We still get 42 *sigh*
NSLog(@"test 5: expecting nil, getting %@", [myUserDefaults objectForKey:@"foo"]);

As you can see, I am trying to remove NSRegistrationDomain from the search list, by invoking both removeSuiteNamed: and removeVolatileDomainForName:. This does not work, at least not on iOS where I ran the tests, but I assume it's the same on Mac OS X. So these are my questions:

  1. On iOS, is there a way to remove one of the five standard domains from the search list of an NSUserDefaults object? Note that it does not necessarily have to be the object returned by standardUserDefaults, I would be happy to create my own object. In case it matters: I am particularly interested in getting rid of NSRegistrationDomain.
  2. If the answer to the above is "no", can we say that the five standard domains are simply "immutable" and that all the stuff in NSUserDefaults about adding/removing suites and persistent/volatile domains is about user-defined domains?
  3. Is there a way to find out what is in the search list of an NSUserDefaults object?

I suspect I already know the answers (no, yes, and no), but at least I am looking for someone with more experience to confirm my suspicions.

herzbube
  • 13,158
  • 9
  • 45
  • 87
  • `NSRegistrationDomain` items are set by the developer, so you are setting them and then want to ignore them? – zaph Feb 06 '12 at 11:29
  • @CocoaFu: Yes, that's right. It's got to do with a class of mine that wants to perform an upgrade of user defaults to a newer format, and I would prefer it if I could write the class in a way that would work regardless of whether or not the registration domain defaults have already been loaded. Please keep in mind, however, that the purpose of asking my question was not to solve this particular problem (I already have a solution), but to get cleared up about whether or not it's possible to modify the standard search list of `NSUserDefaults`. I find the docs rather confusing in this regard. – herzbube Feb 08 '12 at 19:07

2 Answers2

2
  1. To get rid of a domain like NSRegistrationDomain, you should use removeVolatileDomainForName:. However, this will not work with NSRegistrationDomain and NSArgumentDomain. These two cannot be removed. Try to register your own domain with setVolatileDomain:forName: instead. You'll be able to remove this one.

    I believe that in the five domains of the standardUserDefaults, you can remove your own domain with removePersistentDomainForName:, passing your bundle identifier. But I've not tried this out.

    Since NSGlobalDomain is persistent and you can only pass your own bundle identifier to removePersistentDomainForName:, I believe you can't remove NSGlobalDomain. Again, this is untested.

  2. I believe so, except for the persistent domain with your bundle identifier.

  3. No, but using -volatileDomainNames should be sufficient for most purposes.

Thomas Deniau
  • 2,488
  • 1
  • 15
  • 15
  • Thanks. I'm accepting your answer because it confirms what I already suspected. Additional insights are still welcome, though :-) – herzbube Feb 24 '12 at 15:41
0

try calling [myuserDefaults synchronize] right after your modifications