game state singleton cocos2d, initWithEncoder always returns null
        Posted  
        
            by taber
        on Stack Overflow
        
        See other posts from Stack Overflow
        
            or by taber
        
        
        
        Published on 2010-04-19T20:56:12Z
        Indexed on 
            2010/04/20
            0:23 UTC
        
        
        Read the original article
        Hit count: 892
        
Hi, I'm trying to write a basic test "game state" singleton in cocos2d, but for some reason upon loading the app, initWithCoder is never called. Any help would be much appreciated, thanks.
Here's my singleton GameState.h:
#import "cocos2d.h"
@interface GameState : NSObject <NSCoding>
{
  NSInteger level, score;
  Boolean seenInstructions;
}
@property (readwrite) NSInteger level;
@property (readwrite) NSInteger score;
@property (readwrite) Boolean seenInstructions;
+(GameState *) sharedState;
+(void) loadState;
+(void) saveState;
@end
... and GameState.m:
#import "GameState.h"
#import "Constants.h"
@implementation GameState
static GameState *sharedState = nil;
@synthesize level, score, seenInstructions;
-(void)dealloc {
  [super dealloc];
}
-(id)init {
  if(!(self = [super init]))
    return nil;  
  level = 1;
  score = 0;
  seenInstructions = NO;
  return self;
}
+(void)loadState {
  @synchronized([GameState class]) {    
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *saveFile = [documentsDirectory stringByAppendingPathComponent:kSaveFileName];
    Boolean saveFileExists = [[NSFileManager defaultManager] fileExistsAtPath:saveFile];
    if(!sharedState) {
      sharedState = [GameState sharedState];
    }
    if(saveFileExists == YES) {
      [sharedState release];
      sharedState = [[NSKeyedUnarchiver unarchiveObjectWithFile:saveFile] retain];
    }
    // at this point, sharedState is null, saveFileExists is 1
    if(sharedState == nil) {
      // this always occurs
      CCLOG(@"Couldn't load game state, so initialized with defaults");
      sharedState = [self sharedState];
    }
  }  
}
+(void)saveState {
  NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
  NSString *documentsDirectory = [paths objectAtIndex:0];
  NSString *saveFile = [documentsDirectory stringByAppendingPathComponent:kSaveFileName];
  [NSKeyedArchiver archiveRootObject:[GameState sharedState] toFile:saveFile];
}
+(GameState *)sharedState {
  @synchronized([GameState class]) {
    if(!sharedState) {
      [[GameState alloc] init];
    }
    return sharedState;
  }
  return nil;
}
+(id)alloc {
  @synchronized([GameState class]) {
    NSAssert(sharedState == nil, @"Attempted to allocate a second instance of a singleton.");
    sharedState = [super alloc];
    return sharedState;
  }
  return nil;
}
+(id)allocWithZone:(NSZone *)zone
{
  @synchronized([GameState class]) {
    if(!sharedState) {
      sharedState = [super allocWithZone:zone];
      return sharedState;
    }
  } 
  return nil;
}
...
-(void)encodeWithCoder:(NSCoder *)coder {
  [coder encodeInt:level forKey:@"level"];
  [coder encodeInt:score forKey:@"score"];
  [coder encodeBool:seenInstructions forKey:@"seenInstructions"];
}
-(id)initWithCoder:(NSCoder *)coder {
  CCLOG(@"initWithCoder called");
  self = [super init];
  if(self != nil) {
    CCLOG(@"initWithCoder self exists");
    level = [coder decodeIntForKey:@"level"];
    score = [coder decodeIntForKey:@"score"];
    seenInstructions = [coder decodeBoolForKey:@"seenInstructions"];
  }
  return self;
}
@end
... I'm saving the state on app exit, like this:
- (void)applicationWillTerminate:(UIApplication *)application {
  [GameState saveState];
  [[CCDirector sharedDirector] end];
}
... and loading the state when the app finishes loading, like this:
- (BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  ...
  [GameState loadState];
  ...
}
I've tried moving around where I call loadState too, for example in my main CCScene, but that didn't seem to work either.
Thanks again in advance.
© Stack Overflow or respective owner