tech74
tech74

Reputation: 1375

NSKeyedArchiver file - losing data

Using Iphone SDK 3.1.2. I am saving some info to a file using NSKeyedArchiver object. I have 4 keys. I read data from the file for all 4 keys on applicationDidFinshLaunching and write back to the file (all 4 keys) on applicationDidTerminate. Also when the user saves any info i write the data for the particular key its for.

In case there is no file initially i allocate an array for the accountlist, this allows me to add accounts to it.

I am having issues with the file periodically losing the data saved to it. Sometimes its one key affected ie accountlist, sometimes it is the favorites list. It seems to be exacerbated if i just save 1key as opposed to all 4. ive viewed the file using organsier and indeed the data is missing. The thing is many times it does not work. I don't why its so inconsistent. Also if i termintate the debugger in xcode i would expect to only lose recent changes not the whole files data whihc does seem to happen. The whole NSKeyedArchiv er thing seems so flakey im considering maybe another persistent storage strategy. Anyone come across anything like this.

- (void)viewDidLoad 
{

if( self.accountList == nil)
{
    NSMutableArray *array = [[NSMutableArray alloc] init];
    self.accountList = array;
    [array release];
}

if( self.phoneSettings == nil)
{
 PhoneSettings* mySettings = [[PhoneSettings alloc] initSettings];
 self.phoneSettings = mySettings;
 [mySettings release];
}



 NSString *filePath = [self dataFilePath];
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
    NSData *data = [[NSMutableData alloc]
                    initWithContentsOfFile:[self dataFilePath]];
    NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] 
                                     initForReadingWithData:data];
    NSMutableArray *archiveArray = [unarchiver decodeObjectForKey:kDataKey];
 if(archiveArray != nil)
  self.accountList = [archiveArray retain];
 else
  LOG("No archived accounts" ); 

 NSMutableArray *archiveCallList = [unarchiver decodeObjectForKey:kCallListKey];
  if(archiveCallList !=nil)
    appDelegate.callList = [archiveCallList retain];

  NSMutableArray *archiveFavouritesList = [unarchiver   decodeObjectForKey:kfavouritesKey];
  if(archiveFavouritesList != nil)
   appDelegate.favouritesList = [archiveFavouritesList retain];

  PhoneSettings* archiveSettings = [unarchiver decodeObjectForKey:kPhoneSettings];
  if (archiveSettings != nil)
   self.phoneSettings = [archiveSettings retain];

    [unarchiver finishDecoding];          
    [unarchiver release];
    [data release];
}

then in

- (void)applicationWillTerminate:(NSNotification *)notification {

 LOG("Application terminating");
 SessionTalkAppDelegate* appDelegate = (SessionTalkAppDelegate*)[[UIApplication sharedApplication] delegate];




NSMutableData *data = [[NSMutableData alloc] init];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc]
                             initForWritingWithMutableData:data];
[archiver encodeObject:self.accountList forKey:kDataKey];
 [archiver encodeObject:appDelegate.callList forKey:kCallListKey];
 [archiver encodeObject:appDelegate.favouritesList forKey:kfavouritesKey];
 [archiver encodeObject:self.phoneSettings forKey:kPhoneSettings];
[archiver finishEncoding];

[data writeToFile:[self dataFilePath] atomically:YES];
   [archiver release];
[data release];    
}

Upvotes: 3

Views: 2756

Answers (1)

Costique
Costique

Reputation: 23722

You don't need that much code. Save your data:

NSMutableDictionary *appState = [NSMutableDictionary dictionary];
[appState setObject: self.accountList forKey: kDataKey];
[appState setObject: appDelegate.callList forKey: kCallListKey];
[appState setObject: self.phoneSettings forKey: kPhoneSettings];
if ( [NSKeyedArchiver archiveRootObject: appState toFile: [self dataFilePath]] == NO )
    NSLog(@"Failed to archive %@", appState);

Read the data:

NSMutableDictionary *appState = [NSKeyedUnarchiver unarchiveObjectWithFile: [self dataFilePath]];

Note that NSKeyedUnarchiver can raise an NSInvalidArgumentException if the file does not contain a valid archive, so you should enclose the call in a @try{} block.

Upvotes: 4

Related Questions