4

我正在努力将几个位置保存到 plist 文件中以备后用,经过一番谷歌搜索后,我发现 CLLocation 数组本身无法保存,所以我想知道一种方法。

我正在考虑使用几个类将单个 CLLocation 对象“序列化”/“反序列化”到 NSDictionary 中,然后将这些 NSDictionaries 的数组存储到 plist 文件中,但我想知道是否有更好/更智能/更可靠的实现这一目标的方法。

提前致谢。

编辑:

这是我用来将数据保存在 plist 中的函数(c_propertyName 从答案中获取代码)

    - (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];
    }

编辑 2 — 解决方案:

好的,我已经想通了。就在下面,我为我自己的问题发布了一个有两种选择的解决方案。

4

3 回答 3

3

使用 KVC 很容易。

这是获取属性名称的 NSObject 类别的方法(需要<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];
}

然后像这样使用它:

NSArray *keys = [yourLocation c_propertyNames];
NSDictionary *dict = [yourLocation dictionaryWithValuesForKeys:keys];

然后保存该字典。

于 2012-04-19T13:44:05.650 回答
3

我喜欢解决方案 2,但如果所有人都在尝试直接写入文件,则序列化会更简单。

[NSKeyedArchiver archiveRootObject:arrayOfLocations toFile:path];
于 2013-02-19T19:10:02.913 回答
0

经过几个小时的搜索,我已经弄清楚了整个场景。在这里,您有几个解决方案;第一个更“脏”,因为这是我想出的第一个,而第二个更优雅。无论如何,我会把它们都留下,因为也许它们都可以派上用场。

解决方案 — 1

感谢 mit3z 的帮助,我可以将各个部分拼凑起来找出解决方案。

正如他所指出的,您可以将此方法实现到 NSObject 上的一个类别中:

 - (NSArray *)c_propertyNames;

(查看他对这部分代码的回复以及有关它的更多详细信息)

这让我可以自由地做这样的事情:

- (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];
}

需要 superdumb for 循环将 NSDictionary 中的所有数据转换为 NSStrings,以便它们可以毫无问题地写入 plist 文件,如果你只是制作字典然后尝试立即保存它,你不会成功.

通过这种方式,我可以将所有 CLLocation obj“序列化”成一个字典,然后写入一个 plist 文件。

解决方案 — 2

我想出了一个非常简单(也更优雅)的方法:使用NSCoding。由于(我意识到)CLLocation数据类型符合NSCoding的事实,您可以通过NSKeyedArchiver调用数据存档器以获取描述您的数组的 blob,然后将其直接存储到 plist,如下所示:

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];

瞧。就那么简单!:)

基于相同的原则,您可以通过NSKeyUnarchiver轻松取回数据:

self.arrayOfLocations = [[NSMutableArray alloc] initWithArray:[NSKeyedUnarchiver unarchiveObjectWithData: (NSData *)[dict objectForKey:@"LocationList"]]];
于 2012-04-19T22:16:30.867 回答