I am writing a basic game, I am using a GameStateManager
which is a singleton and handles all state management, such as saves, loads, delete methods.
I have a separate singelton which handles all the Game
stuff. The game object is inside the game state manager so I can save it out using NSCoding and Archiving.
When I save the state there appears to be no issues and the Game object (singleton) is saved properly.
However, when I try to load the state (by relaunching the app), the game object is always null.
Strangley, if I remove the singleton properties and make it a standard class, this issue goes away and I can load the class and all its properties without any major issues.
In summary, I do this:
GameStateManager = Singleton, handles all game state management (load, save) and has a game object (game)
Game = Singleton which handles things within the game and has NSCoding protocol employed.
Saving the game state with the game object is fine, the object is clearly there.
Loading the game state seems to make the game object null. It should be there, but for some reason it never loads it.
If I remove all the properties that make the game class a singelton and make it a normal class, the issue seems to go away.
I think it has something to do with the fact that Game
is never init'd, but this does not make sense because I can get Game to load when it has no singleton properties.
Code now follows.
// 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
My question is, how do I successfully save and load an Objective C singelton using NSCoding, and the Archiver?
Edit;
I have tried:
// 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"];
}
and
// 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]);