Objective-C:保留对象,序列化和NSCoding

时间:2011-02-14 22:24:52

标签: iphone objective-c ios memory-management

阅读此代码。我在5分钟内在我的办公桌上写了它,这不是生产代码,只是为了展示。然后在底部阅读我的问题:

@interface SomeClass : NSObject {

NSString *currentFruit;
NSMutableArray *fruits;

}

@property (retain) NSString *currentFruit;
@property (retain) NSMutableArray *fruits;

@end

@implementation SomeClass
@synthesize currentFruit, fruits;

-(void) createArray {

    self.fruits = [[NSMutableArray alloc] initWithObjects:@"apples",@"oranges",@"grapes",nil];
    self.currentFruit = [fruits objectAtIndex:0];
}

-(void)writeToDisk {
    NSString *filePath = @"/somePath/file.ext";
    NSMutableData *fileData = [NSMutableData data];
    NSKeyedArchiver *coder = [[NSKeyedArchiver alloc] initForWritingWithMutableData:fileData];
    [coder encodeObject:self.fruits forKey:@"fruitArray"];
    [coder encodeObject:self.currentFruit forKey:@"theFruit"];
    [coder finishEncoding];
    [fileData writeToFile:filePath atomically:YES];
    [coder release];
}

-(void)loadDataFromDisk {
    NSString *filePath = @"/somePath/file.ext";
    NSData *fileData = [[NSData alloc] initWithContentsOfFile:filePah];
    NSKeyedUnarchiver *decoder = [[NSKeyedUnarchiver alloc] initForReadingWithData:fileData];
    NSMutableArray *decodedFruits = [decoder decodeObjectForKey:@"fruitArray"];
    NSString *decodedFruit = [decoder decodeObjectForKey:@"theFruit"];
    self.currentFruit = decodedFruit;
    self.fruits = decodedFruits;
    [decoder release];
    [fileData release];
}

假设我使用方法 - (void)createArray来创建我的数组,然后将currentFruit的实例设置为数组中的第一个对象。然后我使用 - (void)writeDataToDisk并将对象存储到文件中。当我使用loadDataFromDisk时,我的应用程序是否仍然知道currentFruit应该是我的fruits数组开头的对象?或者我现在会有两个单独的实例?

我想弄明白这一点。我应该跟踪数组索引而不是跟踪实际对象吗?我想始终引用数组中的对象。这有意义吗?

2 个答案:

答案 0 :(得分:2)

尝试使用NSCoding协议使接口混乱。

实现encodeWithCoder和initWithEncoder。 然后,您可以将对象序列化和反序列化为文件或流。

然后你做了以下声明:

NSData *data = [NSKeyedarchiver archivedDataWithRootObject:someClassInstance];

SomeClass *instance = [NSKeyedUnarchiver unarchiveObjectWithData:data];

这不能回答你的问题。但是会使你的代码变得更好。

现在你的问题: 您的申请“不知道”当前的水果。由于loadDataFromDisk位于实例的范围内,因此将覆盖实例变量。换句话说:你有一个实例,你将调用一个方法。它的内容将会改变,不会有第二个实例。 如果需要两个实例,请使用NSCoding协议

当您希望将currentfruit分享到更多实例时,请将currentfruit变量设为静态。

答案 1 :(得分:1)

编辑:我撤回了以下答案,不知何故没有意识到你没有使用NSCoder。以下内容适用于通过实现NSCoding并仅提供单个根对象进行编码。如果您希望在您的情况下工作,它将是文档之外的实现细节,因此不能依赖。

我倾向于相信你会得到同样的对象;当您写出同一对象的多个实例并使用返回原始实例的链接时,存档器会检测到。否则他们将无法编写包含循环引用的任何对象层次结构 - 它们只是永久写入磁盘。因此,对象'theFruit'来自数组'fruitArray'的信息在存档中编码。请参阅'Root Object' within the Archives and Serialization Programming Guide

鉴于您保留了相同的NSKeyedUnarchiver实例,假设下面的代码足够智能以返回相同的对象并不是不合理的。但是,我正在阅读Apple关于存储对象图的重点,并且无法找到对此的明确认可。