I’m making a Cookbook application for the iPad and iPod, and I have an array of my Recipe class in my Cookbook class.
@interface Cookbook : NSObject<NSCoding>{
NSMutableArray* recipes;
}
That’s in my Cookbook class, and in my recipe class I have this:
@interface Recipe : NSObject<NSCoding>{
NSString* name;
NSMutableArray* ingredients; //List of ingredients for the recipe
UIImage* recipePicture;
NSMutableArray* instructions;
unsigned int prepTime;//in seconds
NSDate* dateAdded;
}
(I actually have more variables in here, but I didn’t want to flood this with an excessive amount)
My problem is basically in the save/load feature. I’ve asked a similar question before here:
How can I save an Objective-C object that's not a property list object or is there a better way for this than a property list?
This made me decide it’d be best to use NSCoding, and I’ve already implemented a method for it, too, in accordance with the way that was suggested with NSCoding.
My primary problem is that I can’t get the recipes to be stored and successfully retrieved.
I’ve also had trouble getting the directory to my RecipeList.plist file to store the recipes in.
Any help would be greatly appreciated as this has been the reason I can’t continue making this application.
In my Cookbook.m I have:
-(id) initWithCoder:(NSCoder *)aDecoder{
NSLog(@"Init With Coder - Cookbook");
if(self = [super init]){
recipes = [aDecoder decodeObjectForKey:@"recipes"];
}
return self;
}
In my Recipe.m:
-(id) initWithCoder:(NSCoder *)aDecoder{
if(self = [super init]){
name = [aDecoder decodeObjectForKey:@"name"];
ingredients = [aDecoder decodeObjectForKey:@"ingreds"];
recipePicture = [aDecoder decodeObjectForKey:@"recipePict"];
}
return self;
}
Once again, I have more variables in there, this is just for simplicity.
Also, this is my attempt at getting a file path to RecipeList.plist:
+(NSString*) filePath{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *path = [paths objectAtIndex:0];
path = [path stringByAppendingPathComponent:@"RecipeList.plist"];
NSLog(@"%@",path);
return path;
}
My attempt at a save method in my AppDelegate.m:
-(void) save:(NSString *)path cookbook:(Cookbook *)cookbook{
BOOL b = [[NSFileManager defaultManager] fileExistsAtPath:path];
NSLog(@"File exists: %i",b); //1 = exists, 0 = doesn't
NSMutableData* data = [[NSMutableData alloc] init];
if(data){ //If the data object was successfully initialized
NSKeyedArchiver* archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
if(archiver){
//Encode the recipe using the coder method defined in recipe.
[archiver encodeInt:1 forKey:@"Version"];
[archiver encodeObject:cookbook forKey:@"Cookbook"];
[archiver finishEncoding];
[data writeToFile:path atomically:YES];
}
}
}
and my load method:
-(Cookbook *) loadCookbook:(NSString *)path{
BOOL b = [[NSFileManager defaultManager] fileExistsAtPath:path];
NSLog(@"File exists: %i",b);
Cookbook* ret = nil;
NSData* data = [NSData dataWithContentsOfFile:path];
if(data){
NSKeyedUnarchiver* unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
int version = [unarchiver decodeIntForKey:@"Version"];
if(version == 1){
ret = (Cookbook*) [unarchiver decodeObjectForKey:@"Cookbook"];
}
[unarchiver finishDecoding];
}
return ret;
}
I also have a save and load method for my Recipe class very similar to this.
Once again, any help would be greatly appreciated, and thank you for taking the time to read through this.
EDIT: Here’s the encodeWithCoder method in Recipe.m with a few variables omitted for the sake of brevity:
-(void) encodeWithCoder:(NSCoder *)aCoder{
NSLog(@"Encoding Recipe.");
[aCoder encodeObject:name forKey:@"name"];
[aCoder encodeObject:ingredients forKey:@"ingreds"];
[aCoder encodeObject:recipePicture forKey:@"recipePict"];
[aCoder encodeObject:instructions forKey:@"instructs"];
[aCoder encodeObject:category forKey:@"categ"];
[aCoder encodeObject:dateAdded forKey:@"dateAdd"];
[aCoder encodeInt:prepTime forKey:@"prepTime"];
}
and in Cookbook.m:
-(void) encodeWithCoder:(NSCoder *)aCoder{
NSLog(@"Encoding cookbook.");
[aCoder encodeObject:recipes forKey:@"recipes"];
}
I’ve “almost” copy-pasted your code and after some minor adjustments I’ve got it up and running.
To the Cookbook, I’ve added:
and
You might have those already? I assume you’re instantiating the array somewhere?
Then using this test-routine, the cookbook is created, used and saved perfectly fine:
fyi: I’ve made the Recipe’s instance variables @public for brevity; hopefully you’re using accessors (@property).
Do you use Automatic or Manual reference counting?