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.
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.
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 |
Now lets create our example Task class.
@interface Task : NSObject <NSCoding> | |
@property (nonatomic, strong) NSString *name; | |
- (instancetype)initWithName:(NSString *)name; | |
@end |
@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 |
Now we are able to properly store our tasks in files.
- (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); | |
} | |
} |
- (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); | |
} | |
} |
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" |