Correct way to save/serialize custom objects in iOS

I have a custom object, a UIImageView subclass which has a few gestureRecognizer objects.

If I have a number of these objects stored in a NSMutableArray, how would this array of objects be saved to disk so that it can be loaded when the user runs the app again?

I would like to load the array from the disk and use the objects.


My implementation for something similar is the following and works perfectly :

The custom object (Settings) should implement the protocol NSCoding :

-(void)encodeWithCoder:(NSCoder *)encoder{
    [encoder encodeObject:self.difficulty forKey:@"difficulty"];
    [encoder encodeObject:self.language forKey:@"language"];
    [encoder encodeObject:self.category forKey:@"category"];
    [encoder encodeObject:self.playerType forKey:@"playerType"];
}

- (id)initWithCoder:(NSCoder *)decoder {
    if (self = [super init]) {
        self.difficulty = [decoder decodeObjectForKey:@"difficulty"];
        self.language = [decoder decodeObjectForKey:@"language"];
        self.category = [decoder decodeObjectForKey:@"category"];
        self.playerType = [decoder decodeObjectForKey:@"playerType"];
    }
    return self;
}

The following code writes the custom object to a file (set.txt) and then restores it to the array myArray :

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *appFile = [documentsDirectory stringByAppendingPathComponent:@"set.txt"];

NSMutableArray *myObject=[NSMutableArray array];
[myObject addObject:self.settings];    

[NSKeyedArchiver archiveRootObject:myObject toFile:appFile]; 

NSMutableArray* myArray = [NSKeyedUnarchiver unarchiveObjectWithFile:appFile]; 

//store the array
[NSKeyedArchiver archiveRootObject:myArray toFile:@"someFile"];

//load the array
NSMutableArray* myArray = [NSKeyedUnarchiver unarchiveObjectWithFile:@"someFile"];

Official References.

Note that when the array contains custom object types, you must ensure your type conforms to the NSCoding Protocol before this will work.


This blog post explains how to store an array of custom objects to disk using NSKeyedArchiver and read it back with NSKeyedUnarchiver:

http://www.cocoabuilder.com/archive/cocoa/240775-saving-nsarray-of-custom-objects.html

Apple also has a very helpful guide on the matter, the Archives and Serializations Programming Guide.


I would like to share my improvements to Kostas solution, if somebody needs them.

  1. A class name can be used to generate text file name to store object.
  2. It is a good solution to save objects of a view controller in viewWillDisappear method and restore them in viewDidLoad method.
  3. File name should be generated in separate method to avoid duplicate code.
  4. After restoring object, it should be checked to be not nil.

- (void)viewDidLoad
{
  [super viewDidLoad];

  // Restoring form object from the file
  NSString *formFilePath = [self formFilePath];
  RRCreateResumeForm *form = [NSKeyedUnarchiver unarchiveObjectWithFile:formFilePath];
  if (form != nil) {
    self.formController.form = form;
  }
}


- (void)viewWillDisappear:(BOOL)animated
{
  [super viewWillDisappear:animated];

  // Saving the form object to the file
  NSString *formFilePath = [self formFilePath];
  [NSKeyedArchiver archiveRootObject:self.formController.form toFile:formFilePath];
}


// Returns a file path to the file with stored form data for form controller
- (NSString *)formFilePath
{
  NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
  NSString *documentsDirectory = [paths objectAtIndex:0];
  NSString *formClassName = NSStringFromClass( [self.formController.form class] );
  NSString *formFileName = [NSString stringWithFormat:@"%@.txt", formClassName];
  NSString *formFilePath = [documentsDirectory stringByAppendingPathComponent:formFileName];

  return formFilePath;
}