views:

95

answers:

1

I am writing an iPhone app – a client for some social network. The app support multiple accounts. Info about accounts are stored in a keyed archive.

A method used for saving:

- (void) saveAccounts {
 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
 NSString *path = [paths objectAtIndex:0];
 path = [path stringByAppendingPathComponent:@"accounts.bin"];
 // NSMutableArray *accounts = ...;
 [NSKeyedArchiver archiveRootObject:accounts toFile:path];
}

A method uses for reading:

- (NSMutableArray *) loadAccounts {
 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
 NSString *path = [paths objectAtIndex:0];
 path = [path stringByAppendingPathComponent:@"accounts.bin"];
 NSMutableArray *restoredAccounts = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
 return [restoredAccounts retain];
}

The method saveAccounts is used only if some account is added/modified/deleted. The method loadAccounts is used every time the app starts. There isn't any other code that access this file.

I and one of my testers get an issue. At some moment the starts to act like accounts.bin is missing. If loadAccounts returns nil, the app offers to add an account. After I enter an account (the app must call saveAccounts), the app works normally, but when I launch it again, it asks me to add account again. The only solutions is too reinstall the app to iPhone, after reinstall it works for some time with any troubles.

We (I and my tester who get an issue) use iPhone 3G with 3.1.2. An another tester who didn't experience this issue on his iPhone 3GS with 3.1.2.

Any ideas why this file disappears?

update

I found bug in my code. There was a code that deletes whole Document directory. Because this part of a code is a remote server related, it was hard to trace this code. Bug appeared under very rare conditions only.

Now the bug is found, and the code is corrected. wkw's answer didn't solved my problem, but it forced me to dig deeper. Thank you!

A: 

How about -- as a debugging device --verifying the contents of your Documents directory in loadAccounts or at least whenever the unarchiver returns nil. There's some code below to get the names of files in a directory. Set a breakpoint and just dump the NSArray to view the items.
If you can see that the file exists in the Docs dir, then your problem is elsewhere. Perhaps it did not successfully archive. check the return value on the call to archive the data:

if( ! [NSKeyedArchiver archiveRootObject:accounts toFile:path] ){
    NSLog(@"Oooops! account data failed to write to disk");
}

Get names of files in directory:

- (NSArray*) directoryContentsNames:(NSString*) directoryPath {
    NSArray* result;
    {
        result = [[NSFileManager defaultManager]
            directoryContentsAtPath: directoryPath];
    }
    if( result && [result count] > 0 ){
     NSMutableArray *items = [[[NSMutableArray alloc] init] autorelease];
     for( NSString *name in result ){
      if( ! [name isEqualToString:@".DS_Store"] )
       [items addObject: name];
     }
     result = items;

    }
    return result;
}

Perhaps NSUserDefaults might be easier to use?

Also, is there a reason to use Keyed(Un)Archiver instead of NSArray's writeToFile?

if( ! [accounts writeToFile:path atomically:YES] )
    ; // do something since write failed

and to read the file in:

NSMutableArray *accounts = [[NSArray arrayWithContentsOfFile:path] mutableCopy];
wkw
I have added your suggested debug code. After short time I get an issue again.Now I am sure that contents of Document directory is empty (at least this code returns nothing). Also is missing other files (there was two more files next to `accounts.bin`).Also after I get an issue, I can't archive an array (get `Oooops!` in log).There is no any specific reason why I use KeyedArchiver.
Aleksejs