本文介绍了游戏状态singleton cocos2d,initWithEncoder总是返回null的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 29岁程序员,3月因学历无情被辞! 我试图在cocos2d写一个基本的测试游戏状态单例,但由于某种原因在加载应用程序,initWithCoder不会被调用。 这是我的单身游戏GameState.h: #importcocos2d.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: #importGameState.h #importConstants.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]; } //此时sharedState为null,saveFileExists为1 if(sharedState == nil){ //这总是发生 CCLOG 无法加载游戏状态,所以用默认值初始化); 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,@单例的实例); 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 ...我正在保存状态app exit,like that: - (void)applicationWillTerminate:(UIApplication *)application { [GameState saveState]; [[CCDirector sharedDirector] end]; } ...并加载应用程序加载完成后的状态,如下所示: - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { ... [GameState loadState]; ... } loadstate也是,例如在我的主CCScene,但是似乎也不工作。 再次感谢。解决方案义人!我想我想出来了。加上我找到一个很好的省时的宏来启动: http: //cocoawithlove.com/2008/11/singletons-appdelegates-and-top-level.html 和我使用的修改宏: http://github.com/taberrr/Objective-C-Optimized-Singleton.git (我喜欢sharedGameState超过sharedInstance) 希望这将帮助别人试图做同样的事情...这里是我的工作NSCoder GameState singleton: GameState.h: #importSynthesizeSingleton.h #importcocos2d.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: #importSynthesizeSingleton.h #importGameState.h #importConstants.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]){ //如果loadState在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){ //不需要将结果设置为任何东西,因为我们只是得到initwithCoder被调用。 //如果你尝试覆盖sharedGameState,会抛出一个断言。 [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协议方法 - (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 / strong> - (void)applicationWillTerminate:(UIApplication *)application { ... [GameState saveState]; ... } //在你的应用程序中的某处,也许是在applicationDidFinishLaunching GameState * state = [GameState sharedGameState] ; NSLog(@sharedGameState:%@,state); [GameState loadState]; 如果有人发现任何问题,请PLEASE说。 :) 这似乎工作正常。 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 GameStatestatic 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. 解决方案 Righteous! I think I figured it out. Plus I found a nice time-saving macro to boot: http://cocoawithlove.com/2008/11/singletons-appdelegates-and-top-level.htmlAnd the modified macro I'm using: http://github.com/taberrr/Objective-C-Optimized-Singleton.git (I like "sharedGameState" over "sharedInstance")Hopefully this will help someone else trying to do the same thing... here's my working NSCoder GameState singleton: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;@endGameState.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;}@endSaving:- (void)applicationWillTerminate:(UIApplication *)application { ... [GameState saveState]; ...}Loading:// somewhere in your app, maybe in applicationDidFinishLaunchingGameState *state = [GameState sharedGameState];NSLog(@"sharedGameState: %@", state);[GameState loadState];If someone sees any issues with this, PLEASE speak up. :)It appears to work fine, though. 这篇关于游戏状态singleton cocos2d,initWithEncoder总是返回null的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 上岸,阿里云! 06-23 12:58