我有一个班级,我已经成为一个单身,并且能够使用NSKeyedArchiver保存它的状态,但是我无法绕过它将状态拉回来。
在执行加载的函数中
Venue *venue = [Venue sharedVenue];
NSData *data = [[NSMutableData alloc] initWithContentsOfFile:[self dataFilePath]];
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
venue = [unarchiver decodeObjectForKey:@"Venue"];
[unarchiver finishDecoding];
使用此代码,decodeObjectForKey返回什么?它实际上不是Venue的另一个实例,它不会加载任何已保存的值。在我将它转换为单件保存之前,加载工作正常。
答案 0 :(得分:8)
这就是我认为这是错误的地方。您熟悉NSCoding并且通常通过使用encodeWithCoder:和initWithCoder:overrides使您的对象可编码来实现它。什么使这更简单的是你仍然可以使用NSCoding和NSCoders而不会覆盖这些方法。您可以编码共享对象的状态,而无需编码共享的obejct本身。这可以防止解码共享对象的尴尬问题。
以下是我认为你可以做的一个例子:
@implementation MySharedObject
+ (id)sharedInstance {
static id sharedInstance = nil;
if (!sharedInstance) {
sharedInstance = [[MyClass alloc] init];
}
}
- (id)init {
if ((self = [super init])) {
NSData *data = /* probably from user defaults */
if (data) { // Might not have any initial state.
NSKeyedUnarchiver *coder = [[[NSKeyedUnarchiver alloc] initForReadingWithData:data] autorelease];
myBoolean = [coder decodeBoolForKey:@"MyBoolean"];
myObject = [[coder decodeObjectForKey:@"MyObject"] retain];
[coder finishDecoding];
}
}
return self;
}
- (void)saveState {
NSMutableData *data = [NSMutableData data];
NSKeyedArchiver *coder = [[[NSKeyedArchiver alloc] initForWritingWithMutableData:data] autorelease];
[coder encodeBool:myBoolean forKey:@"MyBoolean"];
[coder encodeObject:myObject forKey:@"MyObject"];
[coder finishEncoding]
// Save the data somewhere, probably user defaults...
}
@end
这里我们有一个共享对象,它使用keyed archive来持久化配置,但我们不对共享对象本身进行编码。这避免了解码单例类的第二个实例的尴尬问题。
答案 1 :(得分:3)
你需要在单例中进行加载这里发生的是你创建单个,你为单例分配一个lval,然后创建一个新对象并将lval重新分配给那个新对象而不修改单例。换句话说:
//Set venue to point to singleton
Venue *venue = [Venue sharedVenue];
//Set venue2 to point to singleton
Venue *venue2 = [Venue sharedVenue];
NSData *data = [[NSMutableData alloc] initWithContentsOfFile:[self dataFilePath]];
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
//Set venue to unarchived object (does not change the singleton or venue2)
venue = [unarchiver decodeObjectForKey:@"Venue"];
[unarchiver finishDecoding];
您要做的是在sharedVenue中处理此问题。人们做单身的方式有两种,所以我不能确定你在做什么,但我们假设sharedVenue目前看起来像这样:
static Venue *gSharedVenue = nil;
- (Venue *) sharedVenue {
if (!gSharedVenue) {
gSharedVenue = [[Venue alloc] init];
}
return gSharedVenue;
}
假设您想要更改它以将对象加载到全局支持单例中:
static Venue *gSharedVenue = nil;
- (Venue *) sharedVenue {
if (!gSharedVenue) {
NSData *data = [[NSMutableData alloc] initWithContentsOfFile:[self dataFilePath]];
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
[data release];
gSharedVenue = [unarchiver decodeObjectForKey:@"Venue"];
[unarchiver finishDecoding];
[unarchiver release];
}
if (!gSharedVenue) {
gSharedVenue = [[Venue alloc] init];
}
return gSharedVenue;
}
显然,您需要以某种方式传达归档目标文件的实际路径。
基于评论的编辑:
好的,如果你使用基于alloc的单例,你需要在init方法中处理这个:
- (id) init {
self = [super init];
if (self) {
NSData *data = [[NSMutableData alloc] initWithContentsOfFile:[self dataFilePath]];
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
[data release];
Venue *storedVenue = [unarchiver decodeObjectForKey:@"Venue"];
[unarchiver finishDecoding];
[unarchiver release];
if (storeVenue) {
[self release];
self = [storedVenue retain];
}
}
return self;
}