Eliasz Sawicki

Eliasz Sawicki

iOS developer from Gdansk

NSKeyedArchiver/Unarchiver

- 1 min

Lately I’ve spent some time wrtiting an app for myself. It is supposed to let you create tasks, mark them as done/undone and then track your progress. I’ve called it “Habit Tracker” and it is available here. While writing this utility I came across a few interesting issues and this blogpost will cover one of them.

Saving and Loading data

The feature that “Habit tracker” surely needed was ability to store and load users tasks. Core data seemed a bit overkill for me, so I decided to use NSKeyedArchiver/Unarchiver.

NSCoding

First of all lets create a class which we want to archive. It will be called Task. In order to save and load it with use of NSKeyedArchiver/Unarchiver we have to make our class implements two methods provided by protocol <NSCoding>.

@protocol NSCoding
- (void)encodeWithCoder:(NSCoder *)aCoder;
- (id)initWithCoder:(NSCoder *)aDecoder; // NS_DESIGNATED_INITIALIZER
@end
view raw Coding.m hosted with ❤ by GitHub

Now lets create our example Task class.

@interface Task : NSObject <NSCoding>
@property (nonatomic, strong) NSString *name;
- (instancetype)initWithName:(NSString *)name;
@end
view raw Task.h hosted with ❤ by GitHub
@implementation Task
- (instancetype)initWithName:(NSString *)name {
self = [super init];
if (self) {
self.name = name;
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)coder {
if (self.name != nil) {
[coder encodeObject:self.name forKey:@"name"];
}
}
- (id)initWithCoder:(NSCoder *)coder {
self = [super init];
if (self != nil) {
self.name = [coder decodeObjectForKey:@"name"];
}
return self;
}
@end
view raw Task.m hosted with ❤ by GitHub

Now we are able to properly store our tasks in files.

Saving

- (void)saveTasks {
NSMutableArray *tasksToSave = [NSMutableArray new];
for (NSInteger i = 0 ; i < 5; i ++) {
NSString *taskName = [NSString stringWithFormat:@"%d", arc4random_uniform(50)];
Task *task = [[Task alloc] initWithName:taskName];
[tasksToSave addObject:task];
}
NSString *path = @"~/Documents/";
path = [path stringByAppendingString:@"FILE_NAME"];
path = [path stringByExpandingTildeInPath];
NSMutableDictionary *rootObject = [NSMutableDictionary dictionary];
rootObject[@"myTasks"] = tasksToSave;
[NSKeyedArchiver archiveRootObject:rootObject toFile:path];
for (NSInteger i = 0; i < tasksToSave.count; i++) {
Task *task = tasksToSave[i];
NSLog(@"Saving task:%@", task.name);
}
}
view raw SaveTasks.m hosted with ❤ by GitHub

Loading

- (void)loadTasks {
NSString *path = @"~/Documents/";
path = [path stringByAppendingString:@"FILE_NAME"];
path = [path stringByExpandingTildeInPath];
NSMutableDictionary *rootObject = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
NSArray *tasks = rootObject[@"myTasks"];
for (NSInteger i = 0; i < tasks.count; i++) {
Task *task = tasks[i];
NSLog(@"Loaded task:%@", task.name);
}
}
view raw LoadTasks.m hosted with ❤ by GitHub

If we use iOS Simulator, all files that are saved by us are stored in our app’s folder. Using my saving code you will find file named “FILE_NAME” under:

/Library/Developer/CoreSimulator/Devices/{DEVICE_ID}/data/Containers/Data/Application/{APP_ID}/Documents

By using this command you can get your currently running iOS Simulator ID:

xcrun simctl list | grep "Booted"

rss facebook twitter github youtube mail spotify lastfm instagram linkedin google google-plus pinterest medium vimeo stackoverflow reddit quora