0

Я пытаюсь написать базовое тестовое «игровое состояние» singleton в cocos2d, но по какой-то причине при загрузке приложения initWithCoder никогда не вызывается. Любая помощь будет высоко оценена, спасибо.game state singleton cocos2d, initWithEncoder всегда возвращает null

Вот мой одноточечно 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, но это тоже не сработало.

Еще раз спасибо.

ответ

5

Праведный! Кажется, я понял это. Кроме того, я нашел хороший экономии времени макрос загрузки: 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 

GameSta te.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]; 

Если кто-то видит какие-либо проблемы с этим, пожалуйста, говорить. :)

Кажется, все нормально работает.

0

Вам не нужно загружать измененный макрос. Исходный allocWithZone возвратил нуль. Просто исправить оригинал так:

от:

+ (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; \ 
} \ 
Смежные вопросы