iPhone - Registered default prefs are not written

2019-09-04 07:30发布

问题:

I have this (much much simplier) code on my app didFinishLaunchingWithOptions :

    NSDictionary *userDefaultsDefaults = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"DefaultsPrefs" ofType:@"plist"]];
    [[NSUserDefaults standardUserDefaults] registerDefaults:userDefaultsDefaults];

    NSLog(@"--------------- NSUserDefaults dump : %@", [prefs dictionaryRepresentation]);
    BOOL a = [[NSUserDefaults standardUserDefaults] synchronize];

But nothing is written... I mean, no pref file is written. If I force [prefs setValue:someValue forKey:@"someKey"];, then the file is created with only this key/value

Why ? How may I set all default preferences then write them to disk ?

BOOL a is YES.
NSLog return the whole DefaultPrefs file content, plus some system values like :

AppleICUForce24HourTime = 1; 
AppleKeyboardsExpanded = 1;

回答1:

How may I set all default preferences then write them to disk ?

why? That nothing is written to disk is the whole point of defaults. They are default values, they are not set by the user, and they can change in a later version of your program.
It's not wanted that they are saved in the preferences file. Once they are saved you can't distinguish between preferences that have been changed by the user and default values, and therefore you can't replace them with newer defaults.

This behaves exactly like it should.

If you want to write to the preferences file use [[NSUserDefaults standardUserDefaults] setObject:foo forKey:bar]

I guess you can use a for loop to do it if you really want.

for (NSString *key in userDefaultsDefaults) {
    [[NSUserDefaults standardUserDefaults] setObject:[userDefaultsDefaults objectForKey:key] forKey:key];
}

But you should reconsider if you really need to save those defaults. I can't think of a valid reason to do this.



回答2:

After duplicating your code and adding more debug statements, it looks things seem to be how you want them. I've created a new View-based project in Xcode 4, added a "DefaultsPrefs.plist" with 5 keys w/NSString default values, and my AppDelegate has been changed to look like this:

 - (IBAction) savePreferences:(id)sender {
    NSUserDefaults* prefs = [NSUserDefaults standardUserDefaults];

    NSLog(@"NSUserDefaults: %@", [prefs dictionaryRepresentation]);

    [prefs synchronize];

    [[NSUserDefaults standardUserDefaults] setObject:@"UpdatedKey1Val" forKey:@"MyKey1"];
    [[NSUserDefaults standardUserDefaults] setObject:@"UpdatedKey2Val" forKey:@"MyKey2"];

    NSLog(@"NSUserDefaults: %@", [prefs dictionaryRepresentation]);
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{        
    self.window.rootViewController = self.viewController;
    [self.window makeKeyAndVisible];

    NSLog(@"MyKey1 before registerDefaults: %@", [[NSUserDefaults standardUserDefaults] objectForKey:@"MyKey1"]); 
    NSLog(@"MyKey2 before registerDefaults: %@", [[NSUserDefaults standardUserDefaults] objectForKey:@"MyKey2"]); 

    NSDictionary *userDefaultsDefaults = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"DefaultsPrefs" ofType:@"plist"]];

    NSLog(@"MyKey1 from userDefaultsDefaults: %@", [userDefaultsDefaults objectForKey:@"MyKey1"]); 
    NSLog(@"MyKey2 from userDefaultsDefaults: %@", [userDefaultsDefaults objectForKey:@"MyKey2"]); 

    [[NSUserDefaults standardUserDefaults] registerDefaults:userDefaultsDefaults];

    NSLog(@"MyKey1 after registerDefaults: %@", [[NSUserDefaults standardUserDefaults] objectForKey:@"MyKey1"]); 
    NSLog(@"MyKey2 after registerDefaults: %@", [[NSUserDefaults standardUserDefaults] objectForKey:@"MyKey2"]); 

    [self savePreferences:nil];

    return YES;
}

With output of (stripping irrelevant pairs from NSUserDefaults):

MyKey1 before registerDefaults: (null)
MyKey2 before registerDefaults: (null)
MyKey1 from userDefaultsDefaults: InitialMyKey1Val
MyKey2 from userDefaultsDefaults: InitialMyKey2Val
MyKey1 after registerDefaults: InitialMyKey1Val
MyKey2 after registerDefaults: InitialMyKey2Val
NSUserDefaults: {

    MyKey1 = InitialMyKey1Val;
    MyKey2 = InitialMyKey2Val;
    MyKey3 = InitialMyKey3Val;
    MyKey4 = InitialMyKey4Val;
    MyKey5 = InitialMyKey5Val;
}

NSUserDefaults: {

    MyKey1 = UpdatedKey1Val;
    MyKey2 = UpdatedKey2Val;
    MyKey3 = InitialMyKey3Val;
    MyKey4 = InitialMyKey4Val;
    MyKey5 = InitialMyKey5Val;
}

If run again, the output starts:

MyKey1 before registerDefaults: UpdatedKey1Val
MyKey2 before registerDefaults: UpdatedKey2Val

This is as expected. You must be doing something else incorrectly because this seems correct.



回答3:

Answer irrelevant due to changed question: My guess is that the file DefaultPrefs is not actually in the application bundle. Check that the plist is part of your Target. You'll be able to tell if it's actually in the bundle by checking what pathForResource:ofType: returns.

NSLog(@"%@", [[NSBundle mainBundle] pathForResource:@"DefaultsPrefs" ofType:@"plist"]]);

This will either output (null) (my guess) or a path. If it's (null), this is your problem. Check here for how to add a resource to a target.