0

我有一个单例类,它将从 Web 服务初始化它的数据,然后将自身保存到一个文件中(使用 NSCoding 和 NSKeyedUnarchiver),这样我就可以初始化这个文件,而不是再次从 Web 中提取所有数据。因为它是一个正在保存的单例实例,所以我希望能够像往常一样调用单例 getter,检查是否有存档副本,如果没有,将数据拉下来并存档。归档工作正常,但是当我尝试调用 [[NSKeyedUnarchiver unarchiveObjectWithFile: filePath] retain] 时,它会在 sharedInstance 初始化之前调用 sharedInstance getter。这会导致 init 被调用,然后应用程序再次下载所有数据,只是随后被取消归档程序覆盖。

我的设置有问题,还是有另一种序列化数据的方法?

这是一些(简化的)代码:

@implementation Helmets
@synthesize helmetList, helmetListVersion;
//Class Fields
static Helmets *sharedInstance = nil;

// Get the shared instance and create it if necessary.
+ (Helmets *)sharedInstance {
    //if(sharedInstance == nil){
        //[Helmets unarchive];             //This does not work! Calls sharedInstance() again (recursion)
        if(sharedInstance == nil){
            sharedInstance = [[super allocWithZone:NULL] init];    //Pull from web service
            [Helmets archive];    //Save instance
        //}
    //}
    return sharedInstance;
}

- (id)init {
    self = [super init];
    if (self) {
            helmetList = [[NSMutableArray alloc]init];

            //Get our data from the web service and save it (excluded)
            }
    }
    return self;
}

//This works!
+(void)archive{
    if([NSKeyedArchiver archiveRootObject:sharedInstance toFile:[Helmets getFilePath]]){
        NSLog(@"Archiving Successful");
    }
    else{
        NSLog(@"Archiving Failed");
    }
}

//This works, but calls getInstance causing data to be downloaded anyways!
+(void)unarchive{
    // Check if the file already exists
    NSFileManager *filemgr = [NSFileManager defaultManager];
    NSString *filePath = [Helmets getFilePath];
    if ([filemgr fileExistsAtPath: filePath])
    {
       sharedInstance = [[NSKeyedUnarchiver unarchiveObjectWithFile: filePath] retain];
    }
    [filemgr release];
}

实例初始化如下:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
    ...
    [Helmets unarchive];        //This calls sharedInstance() too soon!
    [Helmets sharedInstance];
}

该类在 .h 中实现 NSCoding 并覆盖 initWithCoder 和 encodeWithCoder(存档正在工作)。

提前致谢!

4

2 回答 2

2

最后,除了您拥有的共享实例之外,您还需要一个私有方法来设置您的共享实例,并且您需要一个不同的 init,再次对实现私有。

- (id)initAndFetch:(BOOL)fetch
{
    if((self = [super init])) {
        ...

        if(fetch) { do the web fetch };
             ...   
    }
}

在 +sharedInstance 方法中,您将传递 YES。

然后您的解码将如下所示:

- (id)initWithCoder:(NSCoder *)decoder
{
    if((self = [self initAndFetch:NO])) {
        title = [decoder decodeObjectForKey:@"title"];
        ...
        sharedInstance = self;
    }
    return self;
}
于 2012-08-29T21:19:02.877 回答
1

我必须让它以下列方式工作。

-(id)initWithCoder:(NSCoder *)aDecoder
{
    self = [super init];
    if (!self) {
        return nil;
    }
    UserInfo *user =[UserInfo sharedInstance];
    return user;
}

-(void)encodeWithCoder:(NSCoder *)aCoder
{
    UserInfo *user =[UserInfo sharedInstance];
    [aCoder encodeObject: user.phoneNumber   forKey:@"phoneNumber"]; 
}



-(void)save
{
    [[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:[UserInfo sharedInstance]] forKey:@"USER_DATA"];
    [[NSUserDefaults standardUserDefaults]synchronize];

}

-(UserInfo*)currentUser
{
    NSData *data =[[NSUserDefaults standardUserDefaults] objectForKey:@"USER_DATA"];
    UserInfo *savedUser =[NSKeyedUnarchiver unarchiveObjectWithData:data];

    UserInfo *user =[UserInfo sharedInstance];
    return user;
}
于 2016-03-22T06:20:08.217 回答