在自定义getter / setter方法中使用NSKeyedArchiver / Unarchiver

时间:2013-09-15 11:53:31

标签: objective-c cocoa properties nskeyedarchiver

我正在尝试使用NSKeyedArchiver / NSKeyedUnarchiver在文件中存储类属性的数据,以便在启动应用程序之间保持属性的状态。

我在MyClass.h中声明了这样的属性:

@property (nonatomic, weak) NSDictionary *myDictionary;

我在MyClass.m中创建了自定义getter和setter方法,以确保将NSDictionary写入磁盘:

-(NSDictionary *)myDictionary {
    NSDictionary *dictionary;

    NSString *path = [self pathToDataStore];
    if (![[NSFileManager defaultManager] fileExistsAtPath:path]) {
        dictionary = [NSDictionary dictionary];
    } else {
        NSData *archivedData = [NSData dataWithContentsOfFile:path];
        dictionary = [NSKeyedUnarchiver unarchiveObjectWithData:archivedData];
    }

    return dictionary;
}

-(void)setMyDictionary:(NSDictionary *)dictionary {
    NSString *path = [self pathToDataStore];
    NSDictionary *rootObject = [NSDictionary dictionaryWithDictionary:dictionary];
    [NSKeyedArchiver archiveRootObject:rootObject toFile:path];
    self.myDictionary = dictionary;
}

这导致对[self setMyDictionary]的无限循环调用,所以显然我做错了。但是问题是什么?

2 个答案:

答案 0 :(得分:3)

而不是:

self.myDictionary = dictionary;

你应该这样做:

@synthesize myDictionary;
...

-(void)setMyDictionary:(NSDictionary *)dictionary {

...
myDictionary = dictionary
}

您的问题发生原因是:

self.myDictionary = dictionary; 

等于

[self setMyDictionary:dictionary];

答案 1 :(得分:1)

answer from debris解释了为什么在setter中使用self.myDictionary语法导致无限递归(因为“dot”语法只是再次调用setter)并指出相反,你应该在访问器方法中使用实例变量。

话虽如此,还有一些额外的观察。

  1. 您可以收紧现有代码。例如,为什么setter会创建一个新的归档字典?您可以归档传递给setter的dictionary(如果归档因任何原因失败,也可以记录消息)。

    -(void)setMyDictionary:(NSDictionary *)dictionary {
        if (![NSKeyedArchiver archiveRootObject:dictionary toFile:[self pathToDataStore]])
            NSLog(@"%s: archiveRootObject failed", __FUNCTION__);
        _myDictionary = dictionary;
    }
    
  2. 每次引用self.myDictionary getter时,它都会从归档中重新检索,即使它已经被检索过。这是低效的,可能会导致一些意想不到的后果(例如if (self.myDictionary == self.myDictionary)...将失败)。如果没有字典,您可能希望将getter定义为仅从归档中检索字典:

    - (NSDictionary *)myDictionary {
        if (!_myDictionary) {
            NSString *path = [self pathToDataStore];
            if ([[NSFileManager defaultManager] fileExistsAtPath:path]) {
                _myDictionary = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
            }
        }
    
        return _myDictionary;
    }
    
  3. 注意,因为您已经定义了两种访问器方法,所以您可能希望有一条@synthesize行明确定义遵循典型下划线约定的ivar:

    @synthesize myDictionary = _myDictionary;
    
  4. 此外,使用weak内存限定符很奇怪(如果不是这个类,谁拥有此对象?)。我建议将它strong