7

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.

Community
  • 1
  • 1
bsneed
  • 579
  • 4
  • 8
  • That's pretty crazy; let me know if you ever find out why! – Jonathan Sterling Dec 30 '10 at 21:41
  • I have had the exact same issue, with the temporary plists actually ending up filling the iPad completely (thousands of ~4Mb files ending up representing multiple Gb). Definitely looks like an iOS bug. – quentinadam Apr 21 '15 at 13:43

3 Answers3

3

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;
}
bsneed
  • 579
  • 4
  • 8
  • 1
    I have had the exact same issue, with the temporary plists actually ending up filling the iPad completely (thousands of ~4Mb files ending up representing multiple Gb). Definitely an iOS bug. – quentinadam Apr 21 '15 at 13:42
1

Do these plist files persist between application launches? Are you having errors when storing preferences? Does your official plist have write permissions enabled?

Property lists can be written atomically, which means that they are first written to a temporary file and, if there's no error during the write operation, the temporary file is renamed to the original file name. Under normal circumstances, you shouldn’t see the temporary files.

  • The plist files do persist between launches. I'm not seeing any errors storing data, and write permissions are correct. I've seen the temporary files come and go on other apps (seemed normal that they disappear). I've been doing this for years and its the first time i've ever seen this behavior, so its got me really scratching my head. Thanks for the suggestions, hadn't thought to check permissions. – bsneed Dec 30 '10 at 08:41
1

Thought - is the data you are storing being written into the properly named file? I think you implied that it is. I'm wondering if the properly named file is open with write permissions by something other than NSDefaults and if that's blocking the safe save copy from the temp file phase?

Dad
  • 6,388
  • 2
  • 28
  • 34
  • The usual debugging strategy applies, of course; copy the entire project folder and start simplifying by tearing stuff out a little at a time and see when the behavior stops. Get it simple enough and you'll either find your bug, or have a nice demonstration program for Apple's bug reporter :-/ – Dad Jan 01 '11 at 21:40
  • The data is making it into the right file. I don't see that there's any code explicitly opening that file within Gity, but I'll keep looking for that. – bsneed Jan 01 '11 at 21:55
  • Any chance your app isn't running the normal run loop? (like only the modal run loop or something). Or hmm, wonder if you are updating the defaults from multiple threads really often and you're seeing some kind of race condition where second one doesn't happen because first one is in the middle of happening (or something)... Seems more like an os bug at this point though... – Dad Jan 01 '11 at 22:06
  • Tried the binary from http://gityapp.com/ on 10.6.4 and it happens on 10.6.4 also, but only at app exit time is the extra one created. – Dad Jan 01 '11 at 22:18