Я пытаюсь сохранить массив пользовательских спрайтов. Вот мой класс для этого:Сохранение массива пользовательских SKSpriteNodes вызывает BAD ACCESS
SaveData.h
#import <Foundation/Foundation.h>
@interface SaveData : NSObject <NSCoding>
//persistent data
@property (assign, nonatomic) NSMutableArray *treeData;
+(instancetype)sharedSaveData;
-(void)save;
@end
SaveData.m
#import "SaveData.h"
@interface SaveData()
@end
@implementation SaveData
static NSString * const SaveDataTreeKey = @"treedata";
-(instancetype) initWithCoder:(NSCoder *)decoder {
self = [self init];
if (self) {
_treeData = [decoder decodeObjectForKey:SaveDataTreeKey];
if (_treeData == nil) {
_treeData = [NSMutableArray array];
}
}
return self;
}
+(instancetype) sharedSaveData {
static id sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [self loadInstance];
});
return sharedInstance;
}
+(instancetype) loadInstance {
NSData* decodedData = [NSData dataWithContentsOfFile: [SaveData filePath]];
if (decodedData) {
SaveData* saveData = [NSKeyedUnarchiver unarchiveObjectWithData:decodedData];
return saveData;
}
SaveData *data = [[SaveData alloc] init];
if (data.treeData == nil)
data.treeData = [NSMutableArray array];
return data;
}
-(void) encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:self.treeData forKey:SaveDataTreeKey];
}
+(NSString*) filePath {
static NSString* filePath = nil;
if (!filePath) {
filePath =
[[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]
stringByAppendingPathComponent:@"savedata"];
}
return filePath;
}
-(void) save {
NSData* encodedData = [NSKeyedArchiver archivedDataWithRootObject: self];
[encodedData writeToFile:[SaveData filePath] atomically:YES];
}
@end
Я использовал этот код, прежде чем в другом проекте, но я понял, что Я сохранял только типы объектов и примитивов, которые допускает NSCoding (NSNumber, NSDictionary и т. Д.). Я пытаюсь сохранить массив SKSpriteNodes (подклассы).
Подкласс SKSpriteNode имеет пару логических элементов и, конечно же, хранит текстуру, ее размер и местоположение на экране. Вот что я писал для методов NSCoding для моего подкласса под названием Производитель:
"Producer.m"
- (id)initWithCoder:(NSCoder *)decoder {
if (self = [super init]) {
self.isEliminated = [decoder decodeObjectForKey:@"isEliminated"];
self.isPlaced = [decoder decodeObjectForKey:@"isPlaced"];
self.isSelected = [decoder decodeBoolForKey:@"isSeelcted"];
self.isVisible = [decoder decodeBoolForKey:@"isVisible"];
int x = [decoder decodeIntForKey:@"x"];
int y = [decoder decodeIntForKey:@"y"];
self.position = CGPointMake(x, y);
[self createSelectionBox];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeBool:_isSelected forKey:@"isSelected"];
[encoder encodeBool:_isEliminated forKey:@"isEliminated"];
[encoder encodeBool:_isPlaced forKey:@"isPlaced"];
[encoder encodeBool:_isVisible forKey:@"isVisible"];
[encoder encodeInt:self.position.x forKey:@"x"];
[encoder encodeInt:self.position.y forKey:@"y"];
}
"Producer.h"
#import <SpriteKit/SpriteKit.h>
@interface Producer : SKSpriteNode <NSCoding>
@property bool isEliminated;
@property bool isPlaced;
@property bool isSelected;
@property bool isVisible;
-(instancetype) initWithInvisibleState;
-(instancetype) initWithImageNamed:(NSString *)fileName;
-(instancetype) initWithImageFromBundleNamed:(NSString*)fileName;
-(void) select;
-(void) deselect;
@end
В моей первой сцене , объекты-производители создаются, а затем сохраняются в массиве. Я пытаюсь сохранить этот массив путем кодирования с помощью моего класса SaveData.m. Вот вызов (с первой сцены):
-(void) willMoveFromView:(SKView *)view {
[SaveData sharedSaveData].treeData = _tree.data;
[[SaveData sharedSaveData] save];
[self removeAllChildren];
}
_tree.data - массив, который я сохраняю.
В приложение переходит в новую сцену, а затем я пытаюсь извлечь данные из сохраненного файла еще раз, используя класс SaveData по телефону следующее:
NSLog(@"%@", [SaveData sharedSaveData].treeData); //print out data in array
Я не уверен, что я делая ошибку, но я получаю следующую ошибку: Thread 1:EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
. Есть идеи?
Вы добавили точку останова и знаете, какая строка точно выбрасывает ошибку? –
Да, я сделал. Он показывает, что проблема с деревом SaveData treeData является проблемой. Я попытался использовать отладчик, чтобы углубиться в этот вызов, но он ничего не раскрывает. – 02fentym
Я следил за учебником Ray Wenderlich по кодированию игровых данных, и он отлично работал для меня в другом проекте. В любом случае, я скопировал свою хорошую рабочую версию и внес некоторые изменения, и она отлично работает. Я честно не вижу, где проблема была в коде, который я опубликовал. Я уверен, что это небольшая ошибка. – 02fentym