I'm making a game using Cocos2d-iphone 2.1, and have encountered an error with NSCoding unarchiving implementation.
I've used the same pattern in my previous projects (made with UIKit), and everything worked perfetly. While when I'm implementing this pattern on cocos2d, it just doesn't work.
I have recreated the error on a sample project (which can be downloaded here https://www.dropbox.com/sh/30cyfczcxeyf8mr/uDcJiNYMdd ) and here's what I'm doing:
- I've created a simple singleton class "GameStore". Then I've created the "GameParameters" class which is a property of the singleton and conforms to NSCoding (therefore can be archived). In that class there's the "highscore" property of type int (for example) which I'd like to keep archived as a high score value.
- In the GameStore class I initialize the GameParameters instance for the first time, if there's an archived object - I unarchive it.
- In the "HelloWorldLayer" (which is a default cocos2d placeholder class) I call NSLog to display the "highscore" value and then set it to a new value
- In AppDelegate I call the "save data" method to archive data whenever the home button is pressed.
That's it. When I start the app for the first time, everything works well, and I save the data by pressing the home button. And when I start the app again, I run into random (as it seems) EXT_BAD_ACCESS errors... Sometimes when I'm getting the highscore value, sometimes when archiving it again.
Any idea what I might be doing wrong here?
Thanks!
GameStore class
Header file:
#import <Foundation/Foundation.h>
@class GameParameters;
@interface GameStore : NSObject
@property (retain, nonatomic) GameParameters * parameters;
+ (GameStore *) game;
- (void) saveData;
@end
Implementation file:
#import "GameStore.h"
#import "GameParameters.h"
static GameStore * game = nil;
@implementation GameStore
@synthesize parameters;
+ (GameStore *) game
{
if (!game) game = [[super allocWithZone:nil] init];
return game;
}
- (id) init
{
if (game != nil) {
return game;
}
self = [super init];
if (self) {
// Initialization
// Try and load the "GameParameters" from archive
parameters = [NSKeyedUnarchiver unarchiveObjectWithFile:[self archivePath]];
NSLog(@"Highscore: %i",parameters.highscore);
// If there's no archive, initialize the "GameParameters"
if (!parameters) {
parameters = [[GameParameters alloc] init];
parameters.highscore = 12345;
}
}
return self;
}
- (void) saveData
{
[NSKeyedArchiver archiveRootObject:parameters toFile:[self archivePath]];
NSLog(@"Data saved");
}
- (NSString *)archivePath
{
NSArray * documentDirs = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString * documentDir = [documentDirs objectAtIndex:0];
return [documentDir stringByAppendingPathComponent:@"hs.archive"];
}
@end
GameParameters class Header file:
#import <Foundation/Foundation.h>
@interface GameParameters : NSObject <NSCoding>
@property (nonatomic, assign) int highscore;
@end
Implementation file:
#import "GameParameters.h"
@implementation GameParameters
@synthesize highscore;
- (id) initWithCoder:(NSCoder *)aDecoder
{
highscore = [aDecoder decodeIntForKey:@"1"];
return self;
}
- (void) encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeInt:highscore forKey:@"1"];
}
@end