So I’m trying to save an array when the app terminates so that I can re-populate the array when I start back up. I’m running into a lot of different errors though, mostly when I try to recreate the array when the app launches. I have taken steps to encode and decode the custom objects, but maybe i’m not doing it correctly… Here is my code:
- (void)applicationWillTerminate:(UIApplication *)application
{
/*
Called when the application is about to terminate.
Save data if appropriate.
See also applicationDidEnterBackground:.
*/
//Here is Where I save the array. "tasks is a pre-populated array of objects
NSData *taskData = [NSKeyedArchiver archivedDataWithRootObject:tasks];
[[NSUserDefaults standardUserDefaults]setObject:taskData forKey:@"tasks"];
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
tasks = [[NSMutableArray alloc]init];
NSString *appDomain = [[NSBundle mainBundle] bundleIdentifier];
[[NSUserDefaults standardUserDefaults] removePersistentDomainForName:appDomain];
//NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
if([[NSUserDefaults standardUserDefaults] objectForKey:@"tasks"]){
NSData *tasksData = [[NSUserDefaults standardUserDefaults]objectForKey:@"tasks"];
//It usually breaks right here
tasks = [NSKeyedUnarchiver unarchiveObjectWithData:tasksData];
}
Here is the “Task” object that the “tasks” array contains:
Task.h
#import <Foundation/Foundation.h>
@class TeamMember;
@class Project;
@interface Task : NSObject<NSCoding>{
NSDate *endDate;
NSDate *startDate;
NSMutableString* notes;
NSMutableString* taskName;
TeamMember *teamMember;
Project *project;
}
- (void)encodeWithCoder:(NSCoder *)encoder;
- (id)initWithCoder:(NSCoder *)decoder;
@property (nonatomic, retain)TeamMember *teamMember;
@property (nonatomic, retain) Project * project;
@property (nonatomic, retain) NSMutableString *notes;
@property (nonatomic, retain) NSMutableString *taskName;
@property (nonatomic, retain) NSDate *startDate;
@property (nonatomic, retain) NSDate *endDate;
@end
Task.m
#import "Task.h"
@implementation Task
@synthesize notes;
@synthesize taskName;
@synthesize endDate;
@synthesize startDate;
@synthesize teamMember;
@synthesize project;
//@synthesize project;
- (void)encodeWithCoder:(NSCoder *)encoder {
//Encode properties, other class variables, etc
[encoder encodeObject:self.notes forKey:@"notes"];
[encoder encodeObject:self.taskName forKey:@"taskName"];
[encoder encodeObject:self.endDate forKey:@"endDate"];
[encoder encodeObject:self.startDate forKey:@"startDate"];
//you need to add in the encoding for teammember and project
}
- (id)initWithCoder:(NSCoder *)decoder {
if((self = [super init])) {
//decode properties, other class vars
self.notes = [decoder decodeObjectForKey:@"notes"];
self.taskName = [decoder decodeObjectForKey:@"taskName"];
self.endDate = [decoder decodeObjectForKey:@"endDate"];
self.startDate = [decoder decodeObjectForKey:@"startDate"];
//decode teamMember and Project here
}
}
@end
Disregarding the fact that saving such an array to
NSUserDefaultsinstead of using CoreData is poor design, your problem is that you’re not synchronizing the defaults. Add this line[[NSUserDefaults standardUserDefaults] synchronize];at the bottom ofapplicationWillTerminatemethod.And please, use CoreData. User defaults aren’t purposed for data persistence, they’re designed to store a few small chunks of data, like bools, or widths and heights of some specific areas which needs to be restored, not custom user content, that actually needs to be persisted.
Also, do not use
applicationWillTerminatemethod as your resort to saving data, save it right after user adds it. This method does not guarantee that its contents execution will be finished properly.