I am trying to save some persistent data on an iOS app using NSKeyedArchiver to write to a file, and I would like to retrieve this data later using NSKeyedUnarchiver. I created a very basic application to test some code, but with no success. Here are the methods that I am using:
- (void)viewDidLoad
{
[super viewDidLoad];
Note *myNote = [self loadNote];
myNote.author = @"MY NAME";
[self saveNote:myNote]; // Trying to save this note containing author's name
myNote = [self loadNote]; // Trying to retrieve the note saved to the file
NSLog(@"%@", myNote.author); // Always logs (null) after loading data
}
-(NSString *)filePath
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent: @"myFile"];
return filePath;
}
-(void)saveNote:(Note*)note
{
bool success = [NSKeyedArchiver archiveRootObject:note toFile:[self filePath]];
NSLog(@"%i", success); // This line logs 1 (success)
}
-(Note *)loadNote
{
return [NSKeyedUnarchiver unarchiveObjectWithFile:[self filePath]];
}
The class that I am using to test this code is as follows:
Note.h
#import <Foundation/Foundation.h>
@interface Note : NSObject <NSCoding>
@property NSString *title;
@property NSString *author;
@property bool published;
@end
Note.m
#import "Note.h"
@implementation Note
-(id)initWithCoder:(NSCoder *)aDecoder
{
if (self = [super init])
{
self.title = [aDecoder decodeObjectForKey:@"title"];
self.author = [aDecoder decodeObjectForKey:@"author"];
self.published = [aDecoder decodeBoolForKey:@"published"];
}
return self;
}
-(void)encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeObject:self.title forKey:@"title"];
[aCoder encodeObject:self.author forKey:@"author"];
[aCoder encodeBool:self.published forKey:@"published"];
}
@end
I have seen similar examples using NSUserDefaults (https://blog.soff.es/archiving-objective-c-objects-with-nscoding), but I would like to save this data to a file, because as far as I know NSUserDefaults is used mainly to store user preferences, and not general data. Am I missing something? Thanks in advance.
Think about what happens the first time your app runs and you call your loadNote:
method and there isn't anything saved yet.
The line:
Note *myNote = [self loadNote];
will result in myNote
being nil
since nothing was loaded. Now think how that cascades through the rest of your code.
You need to handle this initial case of there being no saved data.
Note *myNote = [self loadNote];
if (!myNote) {
myNote = [[Note alloc] init];
// Setup the initial note as needed
myNote.title = ...
}