3

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];    
}
DShah
  • 9,768
  • 11
  • 71
  • 127
tech74
  • 1,355
  • 3
  • 21
  • 35

1 Answers1

4

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.

Costique
  • 23,712
  • 4
  • 76
  • 79
  • Hi, thanks but what about the other keys, the above code has only archived the accounts lists, i have 3 other lists. What do i do with them Thanks again – tech74 Jan 28 '10 at 18:42
  • Generally you create an NSDictionary (or NSMutableDictionary) containing the data you want to save. Then you pass the dictionary as the root object to NSKeyedArchiver and you get it back from NSKeyedUnarchiver. I have corrected the answer posted above. – Costique Jan 28 '10 at 20:49
  • Thanks, if say i just want to save one key ,say the call list during the app when the user hits save, is the following ok: NSMutableDictionary *appState = [NSMutableDictionary dictionary]; [appState setObject: appDelegate.callList forKey: kCallListKey]; if ( [NSKeyedArchiver archiveRootObject: appState toFile: [self dataFilePath]] == NO ) NSLog(@"Failed to archive %@", appState); – tech74 Jan 28 '10 at 21:47
  • You have to archive *all* your data, not just the changed bits, because NSCoder (and NSKeyedArchiver, for that matter) will overwrite the whole archive anyway. If you need an easier method to store only specific bits of information, maybe you should consider using NSUserDefaults instead. – Costique Jan 29 '10 at 06:47