I\'m developing an app which will save data to the local file system. The data that will be saved will be mostly NSString and NSDate. The data will not be saved that often,
NSUserDefault is good choice if you have only a limited set of data. But if you consider filtering and fetching, then you should have a look to Core Data to store objects.
Even if the object graph is minimal you will gain cached object management and free undo/redo management.
I would suggest that you go with NSUserDefaults
. It's surely the best approach to store information pertaining to your app and any app related data. Check the documentation !!
This kind of data seems to be very simple to store and retrieve and does not have any other dependencies such as a horridly complex object graph.
You should store this data in a flat file or in NSUserDefaults
.
I'll give you an example of both, using object archiving with the use of the NSCoding
protocol:
@interface ApplicationData <NSCopying, NSCoding> {}
@property (nonatomic, strong) NSDate *someDate;
@property (nonatomic, strong) NSDate *someOtherDate;
@property (nonatomic, copy) NSString *someString;
@property (nonatomic, copy) NSString *someOtherString;
@end
@implementation ApplicationData
@synthesize someDate = _someDate, someOtherDate = _someOtherDate, someString = _someString, someOtherString = _someOtherString;
- (NSArray *)keys {
static dispatch_once_t once;
static NSArray *keys = nil;
dispatch_once(&once, ^{
keys = [NSArray arrayWithObjects:@"someString", @"someOtherString", @"someDate", @"someOtherDate", nil];
});
return keys;
}
- (id) copyWithZone:(NSZone *) zone {
ApplicationData *data = [[[self class] allocWithZone:zone] init];
if(data) {
data.someString = _someString;
data.someOtherString = _someOtherString;
data.someDate = _someDate;
data.someOtherDate = _someOtherDate;
//...
}
return data;
}
- (void) encodeWithCoder:(NSCoder *) coder {
[super encodeWithCoder:coder];
NSDictionary *pairs = [self dictionaryWithValuesForKeys:[self keys]];
for(NSString *key in keys) {
[coder encodeObject:[pairs objectForKey:key] forKey:key];
}
}
- (id) initWithCoder:(NSCoder *) decoder {
self = [super initWithCoder:decoder];
if(self) {
for(NSString *key in [self keys]) {
[self setValue:[decoder decodeObjectForKey:key] forKey:key];
}
}
return self;
}
@end
Then, say in your application delegate, you can do this:
@interface AppDelegate (Persistence)
@property (nonatomic, strong) ApplicationData *data;
- (void)saveApplicationDataToFlatFile;
- (void)loadApplicationDataFromFlatFile;
- (void)saveApplicationDataToUserDefaults;
- (void)loadApplicationDataFromUserDefaults;
@end
@implementation AppDelegate (Persistence)
@synthesize data;
- (NSString *)_dataFilePath {
static NSString *path = nil;
static dispatch_once_t once;
dispatch_once(&once, ^{
path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) stringByAppendingPathComponent:@"xAppData.dat"];
});
return path;
}
- (void)loadApplicationDataFromUserDefaults {
NSData *archivedData = [[NSUserDefaults standardUserDefaults] objectForKey:@"appData"];
self.data = [NSKeyedUnarchiver unarchiveObjectWithData:archivedData];
}
- (void)saveApplicationDataToUserDefaults {
NSData *archivedData = [NSKeyedArchiver archivedDataWithRootObject:self.data];
[[NSUserDefaults standardUserDefaults] setObject:archivedData forKey:@"appData"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
- (void)loadApplicationDataFromFlatFile {
NSData *archivedData = [NSData dataWithContentsOfFile:[self _dataFilePath]];
self.data = [NSKeyedUnarchiver unarchiveObjectWithData:archivedData];
}
- (void)saveApplicationDataToFlatFile {
NSData *archivedData = [NSKeyedArchiver archivedDataWithRootObject:self.data];
[archivedData writeToFile:[self _dataFilePath] atomically:YES];
}
@end
Disclaimer: I have not tested this code.