objective-c - 如何使用 NSCoding 加载 Objective C Singleton?

标签 objective-c singleton nskeyedarchiver nscoding

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

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

当我保存状态时,似乎没有问题,并且游戏对象(单例)已正确保存。

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

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

总而言之,我这样做:

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

  2. Game = Singleton,它处理游戏中的事情并使用 NSCoding 协议(protocol)。

  3. 用游戏对象保存游戏状态没问题,对象显然在那里。

  4. 加载游戏状态似乎使游戏对象为空。它应该在那里,但由于某种原因它从未加载它。

  5. 如果我删除所有使游戏类成为单一类的属性并使其成为普通类,问题似乎就消失了。

我认为这与 Game 从未初始化这一事实有关,但这没有意义,因为我可以在 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

我的问题是,如何使用 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"];
}

// 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]);

最佳答案

由于您处理的是单例,因此您只希望该类的单个实例在任何时候都存在。因此,您将只想存档和取消存档该单个实例。

考虑这段代码(假设启用了 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

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

// 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"]];

关于objective-c - 如何使用 NSCoding 加载 Objective C Singleton?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11484062/

相关文章:

ios - 在 -Swift.h 文件中找不到 'UNUserNotificationCenterDelegate' 的协议(protocol)声明

ios - viewForAnnotation 没有被调用(iOS noob)

Objective-C:如何将 bool 值放入 JSON 字典中?

WCF:只允许一个客户端并拒绝其他客户端的服务

ios - 如何截取uiview的屏幕截图并快速拖动?

ios - 未调用自定义 NSObject iniWithCoder

objective-c - 在带有 Cocoa 的 macosx 下使用带有 objective-c 的客户端证书

PHP 跨多个 session 共享对象

java - 如果 `readResolve` 返回调用对象,为什么它是一个实例方法?

ios - 通过 KeyChain 保存和检索值