Saving a Custom Object - RITAccess/accessmath GitHub Wiki

Note: this is done using both NSCoding, NSKeyedArchiver/NSKeyedUnarchiver, and NSUserDefaults.

Model

Assignment Item

Current properties (property name):

  • name (itemName)
  • date created (creationDate)
  • associated lecture (associatedLecture)
  • notes (notes)
  • completed (completed)

Saving Assignment Items

NSCoding is the protocol reference used to encode and decode the instance variables of an object (in this case, Assignment Item). Upon calling this protocol, two methods must be declared in the .m file: initWithCoder: and encodeWithCoder:.

encodeWithCoder: instructs the object to encode its instance variables to the provided coder, and initWithCoder: instructs the object to initialize itself from the data in the provided coder. More information on the NSCoding protocol can be found in the Mac Developer Library: https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Protocols/NSCoding_Protocol/

1) Implement the NSCoding protocol

In the AssignmentItem.h file, the NSCoding protocol is implemented simply by including it between the angle brackets on the @interface line.

AssignmentItem.h
...
#import <Foundation/Foundation.h>

@interface AssignmentItem : NSObject <NSCoding>

@property NSString *itemName;
@property NSDate *creationDate;
@property NSString *associatedLecture;
@property NSString *notes;
@property BOOL completed;
...

Then - in the AssignmentItem.m file - the initWithCoder: and encodeWithCoder: methods are called to initialize and encode the properties of the AssignmentItem respectively.

AssignmentItem.m

#import "AssignmentItem.h"

@implementation AssignmentItem

static NSString* const assignmentName = @"assignment name";
static NSString* const associatedLecture = @"associated lecture";
static NSString* const associatedNotes = @"associated notes";
static NSString* const completed = @"completed";
static NSString* const dueDate = @"due date";

-(instancetype)initWithName:(NSString*)name Date:(NSDate*)creationDate Lecture:(NSString*)associatedLecture {
    self.itemName = name;
    self.creationDate = creationDate;
    self.associatedLecture = associatedLecture;
    self.notes = nil;
    self.completed = NO;
    
    return self;
}

-(instancetype)initWithCoder:(NSCoder *)aDecoder {
    self = [self init];
    if (self) {
        self.itemName = [aDecoder decodeObjectForKey:assignmentName];
        self.creationDate = [aDecoder decodeObjectForKey:dueDate];
        self.associatedLecture = [aDecoder decodeObjectForKey:associatedLecture];
        self.notes = [aDecoder decodeObjectForKey:associatedNotes];
        self.completed = [aDecoder decodeBoolForKey:completed];
    }
    
    return self;
}

-(void)encodeWithCoder:(NSCoder *)aCoder {
    [aCoder encodeObject:self.itemName forKey:assignmentName];
    [aCoder encodeObject:self.creationDate forKey:dueDate];
    [aCoder encodeObject:self.associatedLecture forKey:associatedLecture];
    [aCoder encodeObject:self.notes forKey:associatedNotes];
    [aCoder encodeBool:self.completed forKey:completed];
}

Note that each variable is associated with a unique key so that it can be accurately initialized and encoded.

2) Using NSUserDefaults to save and load the custom objects

In this case, the custom objects being referred to are the students' assignments.

Saving the Assignments

The method to save the assignments is a class method, so that will not need to be instantiated beforehand in order to use it. This method is used to save each new assignment that the student creates as well as preserve their previous assignments.

+ (void)saveAssignment:(AssignmentItem*)assignment {
    //Access the user defaults
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

    //Access the data stored there for the given key
    NSData *dataRepresentingSavedArray = [defaults objectForKey:@"saved array"];

    //Initialize an NSMutableArray
    NSMutableArray *arrayToSave = [[NSMutableArray alloc] init];

   //If there is data previously saved for the given key, create a NSArray with it
   //via NSKeyedUnarchiver and then add them to the new array
    if (dataRepresentingSavedArray != nil) {
        NSArray *oldSavedArray = [NSKeyedUnarchiver unarchiveObjectWithData:dataRepresentingSavedArray];
        for (AssignmentItem *item in oldSavedArray) {
            [arrayToSave addObject:item];
        }
    }

    //Then add the newest assignment created by the student
    [arrayToSave addObject:assignment];

    //Using NSKeyedArchiver, archive the assignments saved to the array into data to be saved
    NSData *encodedObjects = [NSKeyedArchiver archivedDataWithRootObject:arrayToSave];

    //Lastly, store the encoded assignments in defaults with a unique key that can be called to unarchive it
    [defaults setObject:encodedObjects forKey:@"saved array"];
    [defaults synchronize];
}

Loading the Assignments

The loading method will be used to retrieve that data for the saved assignments for the students' use. This is also a class method.

+ (NSMutableArray*)loadAssignments {
    //Access user defaults
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

    //Access the data saved in defaults for the given key
    NSData *encodedObject = [defaults objectForKey:@"saved array"];

    //Initialize a NSMutableArray via NSKeyedUnarchiver to unarchive the data back into the assignments
    NSMutableArray *savedArray = [NSKeyedUnarchiver unarchiveObjectWithData:encodedObject];

    //And return the array
    return savedArray;

}

Current iOS Version for saving custom objects: 9.3

⚠️ **GitHub.com Fallback** ⚠️