views:

301

answers:

2

I'm working on a homework app that uses custom Assignment objects for each assignment. I am trying to store an NSMutableArray (casted to an NSArray via initWithArray:) in standardUserDefaults but I'm having trouble with saving and reloading the array.

I have a table view from which you can choose to add a new assignment (which loads NewAssignmentViewController). When you save the assignment, it is pushed back to an array in AssigmentsViewController. And then you call it every time you load the UITableView which shows the assignments.

Here is the relating code:

-(void)saveToUserDefaults:(NSArray*)myArray{
NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];

if (standardUserDefaults) {
 [standardUserDefaults setObject:[NSKeyedArchiver archivedDataWithRootObject:myArray] forKey:@"Assignments"];
 [standardUserDefaults synchronize];
    }
}

-(void)retrieveFromUserDefaults{
NSUserDefaults *currentDefaults = [NSUserDefaults standardUserDefaults];
NSData *dataRepresentingSavedArray = [currentDefaults objectForKey:@"Assignments"]; 
if (dataRepresentingSavedArray != nil) {
    NSArray *oldSavedArray = [NSKeyedUnarchiver unarchiveObjectWithData:dataRepresentingSavedArray];
 if ([oldSavedArray count] != 0) {
  [assignments setArray:[[NSMutableArray alloc] initWithArray:oldSavedArray]];
 }
 else {
  assignments = [[NSMutableArray alloc] initWithCapacity:100];
 }
}
}
 -(void)backButtonPressed {
[self saveToUserDefaults:[[NSArray alloc] initWithArray:assignments]];
[self.navigationController popViewControllerAnimated:YES];
}

Please help. It does not load the array but does not give any error. Any tips about UserDefault or KeyedArchiver in general would be greatly appreciated.

A: 

I'm not sure if this will fix your problem, but you don't have to pull the array out of Defaults as NSData. Check the NSUserDefaults reference and you'll see that Arrays are valid default objects.

bpapa
A: 

Couple of things here:

If I understand you correctly, you're trying store an array whose contents are the assignment objects.

If you want to serialize these objects for storage into NSUserDefaults, the Assignment objects themselves need to conform the NSCoding protocol by overriding these methods:

- (void)encodeWithCoder:(NSCoder *)encoder;
- (id)initWithCoder:(NSCoder *)decoder;

Since you didn't post the code for your Assignment objects, dunno if you did this properly or at all. If you have you should be able to encode the object. See the Archives and Serializations Programming Guide for more.

As for NSUserDefaults, by my read, you're basically trying to store your application's object model there. Not the best idea. NSUserDefaults is best suited for use with light-weight persistent data: basic preferences, strings, scraps of universal data.

What I would do is write out your archived data to a file and load it when your view loads.

Here's some code from Beginning iPhone Development on that subject:

Creating an archive from an object or objects that conforms to NSCoding is relatively easy. First, we create an instance of NSMutableData to hold the encoded data and then create an NSKeyedArchiver instance to archive objects into that NSMutableData instance:

NSMutableData *data = [[NSMutableData alloc] init]; 
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];

After creating both of those, we then use key-value coding to archive any objects we wish to include in the archive, like this:

[archiver encodeObject:myObject forKey:@”keyValueString”];

Once we’ve encoded all the objects we want to include, we just tell the archiver we’re done, write the NSMutableData instance to the file system, and do memory cleanup on our objects.

[archiver finishEncoding]; BOOL success = [data writeToFile:@”/path/to/archive” atomically:YES]; 
[archiver release]; 
[data release];

To reconstitute objects from the archive, we go through a similar process. We create an NSData instance from the archive file and create an NSKeyedUnarchiver to decode the data: NSData *data = [[NSData alloc] initWithContentsOfFile:path]; NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data]; After that, we read our objects from the unarchiver using the same key that we used to archive the object:

self.object = [unarchiver decodeObjectForKey:@”keyValueString”];

You'd also need to get your application's documents directory to save and load the files.

It's a wildly useful book, full of drop in code snippets. The chapter on persistence might be helpful for you. You might be much happier using Core Data for this task, come to think of it.

Danilo Campos