【问题标题】:game state singleton cocos2d, initWithEncoder always returns null游戏状态单例 cocos2d,initWithEncoder 总是返回 null
【发布时间】:2010-04-19 20:56:12
【问题描述】:

我正在尝试在 cocos2d 中编写一个基本的测试“游戏状态”单例,但由于某种原因,在加载应用程序时,从未调用过 initWithCoder。任何帮助将不胜感激,谢谢。

这是我的单例 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

... 和 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

...我正在保存应用退出时的状态,如下所示:


- (void)applicationWillTerminate:(UIApplication *)application {
  [GameState saveState];
  [[CCDirector sharedDirector] end];
}

...并在应用完成加载时加载状态,如下所示:


- (BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  ...
  [GameState loadState];
  ...
}

我也尝试过在我调用 loadState 的地方移动,例如在我的主 CCScene 中,但这似乎也不起作用。

再次提前致谢。

【问题讨论】:

    标签: iphone-sdk-3.0 singleton cocos2d-iphone nsdata nskeyedarchiver


    【解决方案1】:

    正义!我想我想通了。另外,我发现了一个不错的启动宏:http://cocoawithlove.com/2008/11/singletons-appdelegates-and-top-level.html

    我正在使用修改后的宏:http://github.com/taberrr/Objective-C-Optimized-Singleton.git(我喜欢“sharedGameState”而不是“sharedInstance”)

    希望这会帮助其他人尝试做同样的事情......这是我工作的 NSCoder GameState 单例:

    GameState.h:

    
    #import "SynthesizeSingleton.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;
    
    SYNTHESIZE_SINGLETON_FOR_CLASS_HEADER(GameState);
    
    +(void)loadState;
    +(void)saveState;
    
    @end
    

    GameState.m:

    
    #import "SynthesizeSingleton.h"
    #import "GameState.h"
    #import "Constants.h"
    
    @implementation GameState
    
    @synthesize level, score, seenInstructions;
    
    SYNTHESIZE_SINGLETON_FOR_CLASS(GameState);
    
    - (id)init {
      if((self = [super init])) {
    
        self.level = 1;
        self.score = 0;
        self.seenInstructions = NO;
    
      }
      return self;
    }
    
    +(void)loadState
    {
      @synchronized([GameState class]) {
        // just in case loadState is called before GameState inits
        if(!sharedGameState)
          [GameState sharedGameState];
    
        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        NSString *documentsDirectory = [paths objectAtIndex:0];
        NSString *file = [documentsDirectory stringByAppendingPathComponent:kSaveFileName];
        Boolean saveFileExists = [[NSFileManager defaultManager] fileExistsAtPath:file];
    
        if(saveFileExists) {
          // don't need to set the result to anything here since we're just getting initwithCoder to be called.
          // if you try to overwrite sharedGameState here, an assert will be thrown.
          [NSKeyedUnarchiver unarchiveObjectWithFile:file];
        }
      }
    }
    
    +(void)saveState
    {
      @synchronized([GameState class]) {  
        GameState *state = [GameState sharedGameState];
    
        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        NSString *documentsDirectory = [paths objectAtIndex:0];
        NSString *saveFile = [documentsDirectory stringByAppendingPathComponent:kSaveFileName];
    
        [NSKeyedArchiver archiveRootObject:state toFile:saveFile];
      }
    }
    
    #pragma mark -
    #pragma mark NSCoding Protocol Methods
    
    -(void)encodeWithCoder:(NSCoder *)coder
    {
      [coder encodeInt:self.level forKey:@"level"];
      [coder encodeInt:self.score forKey:@"score"];
      [coder encodeBool:self.seenInstructions forKey:@"seenInstructions"];
    }
    
    -(id)initWithCoder:(NSCoder *)coder
    {
      self = [super init];
      if(self != nil) {
        self.level = [coder decodeIntForKey:@"level"];
        self.score = [coder decodeIntForKey:@"score"];
        self.seenInstructions = [coder decodeBoolForKey:@"seenInstructions"];
      }
      return self;
    }
    
    @end
    

    保存:

    
    - (void)applicationWillTerminate:(UIApplication *)application {
      ...
      [GameState saveState];
      ...
    }
    

    加载中:

    
    // somewhere in your app, maybe in applicationDidFinishLaunching
    GameState *state = [GameState sharedGameState];
    NSLog(@"sharedGameState: %@", state);
    [GameState loadState];
    

    如果有人对此有任何疑问,请说出来。 :)

    不过,它似乎工作正常。

    【讨论】:

      【解决方案2】:

      您无需下载修改后的宏。原来的 allocWithZone 返回 nil。只需像这样更正原始的:

      来自:

      + (id)allocWithZone:(NSZone *)zone \
      { \
          @synchronized(self) \
          { \
              if (shared##classname == nil) \
              { \
                  shared##classname = [super allocWithZone:zone]; \
                  return shared##classname; \
              } \
          } \
          \
          return nil; \
      } \
      

      到:

      + (id)allocWithZone:(NSZone *)zone \
      { \
          @synchronized(self) \
          { \
              if (shared##classname == nil) \
              { \
                  shared##classname = [super allocWithZone:zone]; \
              } \
          } \
          \
          return shared##classname; \
      } \
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多