Unarchiving SKSpriteNode corrupts the SKTexture of a sprite in iOS 7.1, otherwise
I am using a NSKeyedArchiver
zip file NSMutableDictionary
that contains a NSMutableArray
subclass of SKSpriteNode
s. Its a card game in which I save the game stats and then an array of game related sprites.
The archive works very well. I also implement - (id)initWithCoder:(NSCoder *)aDecoder
and - (void)encodeWithCoder:(NSCoder *)aCoder
in my subclass SKSpriteNode
to make sure all properties, including the sprite texture, are archive-encoded.
The problem is when I unlock the game data. In my iOS 8 NSMutableArray
of SKSpriteNode
unpacked just fine and is added back into the game with their textures and qualities in tact.
However, in iOS 7.1 everything is unpacked except for the node texture. Instead, I get the error: SKTexture: Error loading image resource: "MissingResource.png"
and my sprites have a big red X instead of their textures.
Here's my code:
Archive:
- (void)applicationDidEnterBackground:(UIApplication *)application
{
SKView *view = (SKView *)self.window.rootViewController.view;
if( view.scene ) {
GameScene* game = (GameScene*)view.scene;
NSMutableDictionary* currentGame = [[NSMutableDictionary alloc] init];
// game stats
[currentGame setObject:[[Global getSharedInstance] undoStack] forKey:@"undoStack"];
[currentGame setObject:[NSNumber numberWithInt:game.hints] forKey:@"remainingHints"];
[currentGame setObject:[NSNumber numberWithInt:game.undos] forKey:@"remainingUndos"];
[currentGame setObject:[NSNumber numberWithInt:[[Global getSharedInstance] moves]] forKey:@"gameMoves"];
[currentGame setObject:[NSNumber numberWithInt:[[Global getSharedInstance] score]] forKey:@"gameScore"];
[currentGame setObject:[NSNumber numberWithInteger:[[Global getSharedInstance] elapsedTime]] forKey:@"elapsedTime"];
[currentGame setObject:[NSNumber numberWithInteger:[[Global getSharedInstance] minutes]] forKey:@"minutes"];
[currentGame setObject:[NSNumber numberWithInteger:[[Global getSharedInstance] startedTimeInterval]] forKey:@"startedTimeInterval"];
[currentGame setObject:[NSNumber numberWithInteger:[[Global getSharedInstance] elapsedPauseTime]] forKey:@"elapsedPauseTime"];
[currentGame setObject:[NSNumber numberWithInteger:[[Global getSharedInstance] lastPauseTime]] forKey:@"lastPauseTime"];
// here - game cards SKSpriteNodes
[currentGame setObject:game.cards forKey:@"cards"];
// encode to disk
NSData* encodedData = [NSKeyedArchiver archivedDataWithRootObject:currentGame];
[encodedData writeToFile:[Global gameDataFilePath] atomically:YES];
}
}
Sprite encoding
- (id)initWithCoder:(NSCoder *)aDecoder
{
NSLog(@"%@",[aDecoder decodeObjectForKey:@"texture"]);
self = [super initWithTexture:[aDecoder decodeObjectForKey:@"texture"] color:[UIColor clearColor] size:CGSizeMake(106,156)];
if(self) {
self.name = [aDecoder decodeObjectForKey:@"name"];
self.theme = [aDecoder decodeObjectForKey:@"theme"];
self.suit = [aDecoder decodeObjectForKey:@"suit"];
self.value = [aDecoder decodeIntForKey:@"value"];
self.ID = [aDecoder decodeIntForKey:@"ID"];
self.locked = [aDecoder decodeBoolForKey:@"locked"];
self.faceUp = [aDecoder decodeBoolForKey:@"faceUp"];
self.black = [aDecoder decodeBoolForKey:@"black"];
self.dealCard = [aDecoder decodeBoolForKey:@"dealCard"];
self.highlighted = [aDecoder decodeBoolForKey:@"highlighted"];
self.highlightAction = [aDecoder decodeObjectForKey:@"highlightAction"];
self.inStackNode = [aDecoder decodeObjectForKey:@"inStackNode"];
self.shadowNode = [aDecoder decodeObjectForKey:@"shadowNode"];
self.highlightNode = [aDecoder decodeObjectForKey:@"highlightNode"];
self.zPosition = [aDecoder decodeFloatForKey:@"zPosition"];
[self addChild:self.shadowNode];
[self addChild:self.inStackNode];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeObject:self.theme forKey:@"theme"];
[aCoder encodeObject:self.suit forKey:@"suit"];
[aCoder encodeInt:self.value forKey:@"value"];
[aCoder encodeInt:self.ID forKey:@"ID"];
[aCoder encodeBool:self.black forKey:@"black"];
[aCoder encodeBool:self.locked forKey:@"locked"];
[aCoder encodeBool:self.faceUp forKey:@"faceUp"];
[aCoder encodeBool:self.dealCard forKey:@"dealCard"];
[aCoder encodeBool:self.highlighted forKey:@"highlighted"];
[aCoder encodeObject:self.highlightAction forKey:@"highlightAction"];
[aCoder encodeObject:self.inStackNode forKey:@"inStackNode"];
[aCoder encodeObject:self.shadowNode forKey:@"shadowNode"];
[aCoder encodeObject:self.highlightNode forKey:@"highlightNode"];
[aCoder encodeObject:self.name forKey:@"name"];
[aCoder encodeFloat:self.xScale forKey:@"scale"];
[aCoder encodeFloat:self.zPosition forKey:@"zPosition"];
[aCoder encodeObject:self.texture forKey:@"texture"];
}
NSLog()
in method - (id)initWithCoder:(NSCoder *)aDecoder
prints correct SKTexture in iOS 8 and prints SKTexture Missing Image in iOS 7.
Thoughts?
source to share
Following on from my own question, I decided instead to save the game state to [NSUserDefaults standardUserDefaults]
and [NSUbiquitousKeyValueStore defaultStore]
for iCloud. I now save an NSMutableArray
of NSMutableDictionary
representing my map's attributes in the user's defaults, and then I restore my sprites from those values ββwhen it comes time to revive the saved game.
Everything works as it does now.
source to share