Reputation: 579
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.
Upvotes: 7
Views: 1871
Reputation: 579
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;
}
Upvotes: 3
Reputation: 6468
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?
Upvotes: 1
Reputation:
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.
Upvotes: 1