如何使用NSCoding加载Objective C Singleton?

zar*_*don 3 singleton objective-c nscoding nskeyedarchiver

我正在编写一个基本游戏,我使用的GameStateManager是一个单例并处理所有状态管理,例如保存,加载,删除方法.

我有一个单独的singelton处理所有的Game东西.游戏对象位于游戏状态管理器内部,因此我可以使用NSCoding和Archiving将其保存.

当我保存状态时,似乎没有问题,Game对象(单例)被正确保存.

但是,当我尝试加载状态(通过重新启动应用程序)时,游戏对象始终为null.

Strangley,如果我删除单例属性并使其成为标准类,这个问题就会消失,我可以加载类及其所有属性而不会出现任何重大问题.

总之,我这样做:

  1. GameStateManager = Singleton,处理所有游戏状态管理(加载,保存)并具有游戏对象(游戏)

  2. Game = Singleton,用于处理游戏中的事物并使用NSCoding协议.

  3. 用游戏对象保存游戏状态很好,对象显然就在那里.

  4. 加载游戏状态似乎使游戏对象为空.它应该存在,但由于某种原因它永远不会加载它.

  5. 如果我删除所有使游戏类成为singelton并使其成为正常类的属性,问题似乎就会消失.

我认为它与Game从未初始化的事实有关,但这没有意义,因为我可以在没有单例属性时加载游戏.

现在的代码如下.

// GameStateManager.m

-(void)saveGameState
{
    CCLOG(@"METHOD: saveGameState()");

    self.lastSaveDate   = [NSDate date];

    NSMutableData *data;
    NSString *archivePath = [NSTemporaryDirectory() stringByAppendingPathComponent:kGameSaveFile];
    NSKeyedArchiver *archiver;
    BOOL result;

    data = [NSMutableData data];
    archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];

    [archiver encodeObject:self.lastSaveDate forKey:@"lastSaveDate"];
    [archiver encodeObject:self.game forKey:@"game"];
    [archiver finishEncoding];
    result = [data writeToFile:archivePath atomically:YES];
    [archiver release];

}

-(void)loadGameState
{
    CCLOG(@"METHOD: loadGameState()");


    NSData *data;
    NSKeyedUnarchiver *unarchiver;
    NSString *archivePath = [NSTemporaryDirectory() stringByAppendingPathComponent:kGameSaveFile];

    data = [NSData dataWithContentsOfFile:archivePath];
    unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];

    // Customize unarchiver here
    self.game = [unarchiver decodeObjectForKey:@"game"];
    self.lastSaveDate = [unarchiver decodeObjectForKey:@"lastSaveDate"];

    [unarchiver finishDecoding];
    [unarchiver release];


    CCLOG(@"Last Save Date = %@", self.lastSaveDate);
    NSLog(@"game = %@", self.game);
}

// END OF GAMESTATEMANAGER

// -------------------------

 // Game.h
    @interface Game : NSObject
<NSCoding>
{
    NSMutableArray *listOfCities;
    NSMutableArray *listOfColors;
    NSMutableArray *listOfPlayers;
}

@property (nonatomic, retain) NSMutableArray *listOfCities;
@property (nonatomic, retain) NSMutableArray *listOfColors;
@property (nonatomic, retain) NSMutableArray *listOfPlayers;

+(Game *) sharedGame;


 //
// Game.m
// This is a cut-down version of the game object
// Game is a singelton
// The listOfCities, etc are arrays
//
@implementation Game
SYNTHESIZE_SINGLETON_FOR_CLASS(Game)
@synthesize listOfCities, listOfPlayers;

#pragma mark - NSCoding


-(id)initWithCoder:(NSCoder *)aDecoder
{
    self = [super init];

    if (self) 
    {
        self.listOfCities = [aDecoder decodeObjectForKey:@"listOfCities"];
        self.listOfPlayers = [aDecoder decodeObjectForKey:@"listOfPlayers"];

        NSLog(@"Cities = %d", [self.listOfCities count]);
        NSLog(@"Players = %d", [self.listOfPlayers count]);
    }

    return self;
}

-(void)encodeWithCoder:(NSCoder *)aCoder
{
    // Archive objects
    NSLog(@"Cities = %d", [self.listOfCities count]);
    NSLog(@"Players = %d", [self.listOfPlayers count]);

    [aCoder encodeObject:self.listOfCities forKey:@"listOfCities"];
    [aCoder encodeObject:self.listOfPlayers forKey:@"listOfPlayers"];
}

@end
Run Code Online (Sandbox Code Playgroud)

我的问题是,如何使用NSCoding和Archiver成功保存和加载Objective C singelton?

编辑;

我试过了:

// In the GameStateManager
#pragma mark - NSCoding

-(id)initWithCoder:(NSCoder *)decoder {
    if (self = [super init]) {
        self.lastSaveDate = [[decoder decodeObjectForKey:@"lastSaveDate"] retain];
        self.game = [[decoder decodeObjectForKey:@"game"] retain];
    }
    return self;
}
-(void)encodeWithCoder:(NSCoder *)encoder {
    [encoder encodeObject:self.lastSaveDate forKey:@"lastSaveDate"];
    [encoder encodeObject:self.game forKey:@"game"];
}
Run Code Online (Sandbox Code Playgroud)

// In Game.m
    self.listOfCities = [[aDecoder decodeObjectForKey:@"listOfCities"] retain];
        self.listOfPlayers = [[aDecoder decodeObjectForKey:@"listOfPlayers"] retain];

        NSLog(@"Cities = %d", [self.listOfCities count]);
        NSLog(@"Players = %d", [self.listOfPlayers count]);
Run Code Online (Sandbox Code Playgroud)

Eri*_*ker 6

由于您正在处理单例,因此您只需要在任何时候存在该类的单个实例.因此,您只想归档和取消归档该单个实例.

考虑这段代码(假设启用了ARC):

@interface Singleton : NSObject <NSCoding>

+ (id)sharedInstance;
@property (strong, nonatomic) NSString *someString;

@end

@implementation Singleton

+ (id)sharedInstance {
    static Singleton instance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[Singleton alloc] init];
    });
    return instance;
}

#pragma mark - NSCoding implementation for singleton

- (id)initWithCoder:(NSCoder *)aDecoder {
    // Unarchive the singleton instance.
    Singleton *instance = [Singleton sharedInstance];

    [instance setSomeString:[aDecoder decodeObjectForKey:@"someStringKey"]];

    return instance;
}

- (void)encodeWithCoder:(NSCoder *)aCoder {
    // Archive the singleton instance.
    Singleton *instance = [Singleton sharedInstance];

    [aCoder encodeObject:[instance someString] forKey:@"someStringKey"]];
}

@end
Run Code Online (Sandbox Code Playgroud)

使用此模板,您可以归档/取消归档单例,如下所示:

// Archiving calls encodeWithCoder: on the singleton instance.
[[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:[Singleton sharedInstance]] forKey:@"key"];

// Unarchiving calls initWithCoder: on the singleton instance.
[[NSKeyedUnarchiver unarchiveObjectWithData:[[NSUserDefaults standardUserDefaults] objectForKey:@"key"]];
Run Code Online (Sandbox Code Playgroud)