Reputation: 2557
I'm struggling to save several locations into a plist file for later use, after a bit of googling I discovered that an array of CLLocation per se cannot be saved, so I was wondering about a way to do it.
I was thinking about a couple of classes to "serialize"/"deserilize" a single CLLocation object into an NSDictionary and then store an array of those NSDictionaries into the plist file, but I was wondering if there could be a better/smarter/reliable way to achieve that.
thanks in advance.
EDIT:
this is the function I use to save the data in the plist (the c_propertyName takes the code from the answer)
- (void) addLocation {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:@"/Locations.plist"];
NSArray *keys = [curLocation c_propertyNames];
NSDictionary *dict = [curLocation dictionaryWithValuesForKeys:keys];
[dict writeToFile: path atomically:YES];
}
EDIT 2 — SOLUTIONS:
Ok, I've figured all out. right below, I've posted a two-optioned solution to my own question.
Upvotes: 4
Views: 1912
Reputation: 6251
I like solution 2 but serialization can be simpler if all one is trying to do is write straight to a file.
[NSKeyedArchiver archiveRootObject:arrayOfLocations toFile:path];
Upvotes: 3
Reputation: 2557
after some hours of search I've figured out the entire scenario. Here you got a couple of solutions; the first is the more "dirty", because it's the first I've came up with, while the second is the more elegant. Anyway, I'll leave'em both because maybe they could both come in handy to somebody.
S O L U T I O N — 1
Thanks to the help of mit3z I could put together the pieces to figure out a solution.
as he points out, you can implement this method into a category on the NSObject:
- (NSArray *)c_propertyNames;
( look at his response for this part's code and further more details about it )
this gives me the liberty to do such thing:
- (void) addLocation {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:@"/Locations.plist"];
NSArray *keys = [curLocation c_propertyNames]; // retrieve all the keys for this obj
NSDictionary *values = [self.curLocation dictionaryWithValuesForKeys:keys];
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
for(NSString *key in keys) {
NSString *aaa = [NSString stringWithFormat:@"%@", (NSString *)[values valueForKey:key]];
[dict setValue:aaa forKey:key];
}
[dict writeToFile:path atomically:YES];
}
the superdumb for loop is needed to convert all the data in the NSDictionary into NSStrings so that they can be written into the plist file without troubles, if you just make the dictionary and then you attempt to save it right away, you wan't succeed.
In this way I can have all the CLLocation obj "serialized" into a dict and then written into a plist file.
S O L U T I O N — 2
I came up with a really easiest (and more elegant) way to do so: using the NSCoding. Because of the fact (that I realized that)the CLLocation datatype conforms NSCoding, you can invoke the data archiver via NSKeyedArchiver to get a blob describing your array and then store it right to the plist, like that:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:@"/Locations.plist"];
NSMutableDictionary *data = [[NSMutableDictionary alloc] initWithContentsOfFile: path];
[data setValue:[NSKeyedArchiver archivedDataWithRootObject:arrayOfLocations] forKey:@"LocationList"];
[data writeToFile:path atomically:YES];
[data release];
and voila'. simple as that! :)
based on the same principles you can easily get back your data, via NSKeyUnarchiver:
self.arrayOfLocations = [[NSMutableArray alloc] initWithArray:[NSKeyedUnarchiver unarchiveObjectWithData: (NSData *)[dict objectForKey:@"LocationList"]]];
Upvotes: 0
Reputation: 1904
It's quite easy with KVC.
Here's method of NSObject category to get property names (requires <objc/runtime.h>
)
- (NSArray *)c_propertyNames {
Class class = [self class];
u_int count = 0;
objc_property_t *properties = class_copyPropertyList(class, &count);
if (count <= 0) {
return nil;
}
NSIndexSet *set = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, count)];
NSMutableSet *retVal = [NSMutableSet setWithCapacity:count];
[set enumerateIndexesWithOptions:NSEnumerationConcurrent
usingBlock:^(NSUInteger idx, BOOL *stop) {
const char *propName = property_getName(properties[idx]);
NSString *name = [NSString stringWithUTF8String:propName];
[retVal addObject:name];
}];
return [retVal allObjects];
}
then use it like this :
NSArray *keys = [yourLocation c_propertyNames];
NSDictionary *dict = [yourLocation dictionaryWithValuesForKeys:keys];
then save that dictionary.
Upvotes: 3