Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is NSUserDefaults leaving temporary plist files in Library/Preferences for my app?

I'm having trouble figuring out why NSUserDefaults is leaving junk plist files in Library/Preferences for my app.

I'm seeing the following files...

com.mycompany.myapp.plist
com.mycompany.myapp.plist.3gaPYul
com.mycompany.myapp.plist.c97yxEH

... etc. The plist.* files are 0 bytes. It seems that everytime the app is run, it leaves a new one behind. I made sure I'm not calling -[NSUserDefaults synchronize] at all, however if I do call it, it hastens the junk files appearance for a given run. Stepping through in a debugger, as soon as i step over the call to synchronize, a new file has appeared. If I take out the synchronize call, a new junk file appears sometimes on app start, other times on app quit.

I'm also checking to see if maybe I'm setting a user default on a thread (unlikely, but a possibility perhaps), thought the docs say it is thread safe.

Any help is appreciated. Thanks!

EDIT:

Just found this: CFPreferences creates multiple files

While I agree with the answerers idea, it doesn't explain the "Why?" part.

like image 944
bsneed Avatar asked Dec 30 '10 08:12

bsneed


1 Answers

I've become convinced this is an Apple bug, but i've been unable to craft a small sample illustrating it. I've gotten a ton of feedback saying Apple's own apps do this. Since i've kind of hit a wall and need to keep moving, i've ended up doing a nasty hack shown below.

@implementation NSUserDefaults(Hack)

- (BOOL)synchronize
{
BOOL result = CFPreferencesAppSynchronize((CFStringRef)[[NSBundle mainBundle] bundleIdentifier]);
if (!result)
{
    // there's probably a temp file lingering around... try again.
    result = CFPreferencesAppSynchronize((CFStringRef)[[NSBundle mainBundle] bundleIdentifier]);

    // regardless of the result, lets clean up any temp files hanging around..
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSString *prefsDir = [NSHomeDirectory() stringByAppendingPathComponent:@"Library/Preferences"];
    NSDirectoryEnumerator *dirEnumerator = [fileManager enumeratorAtPath:prefsDir];
    NSString *file = nil;
    NSString *match = [[[NSBundle mainBundle] bundleIdentifier] stringByAppendingString:@".plist."];
    while ((file = [dirEnumerator nextObject]))
    {
        if ([file rangeOfString:match].location != NSNotFound)
        {
            NSString *fileToRemove = [prefsDir stringByAppendingPathComponent:file];
            [fileManager removeItemAtPath:fileToRemove error:nil];
        }
    }
}

return result;
}
like image 118
bsneed Avatar answered Sep 29 '22 06:09

bsneed