Сбои приложения (EXC_BAD_ACCESS) при загрузке настроек в @Property - PullRequest
0 голосов
/ 29 мая 2011

это один из многих вопросов EXC_BADACCES, но я долгое время проводил исследования и думаю, что на этот вопрос еще не ответили. Мое приложение сохраняет данные в настройках. Все идет хорошо, если я удаляю настройки и запускаю приложение, чтобы вообще не происходила загрузка. Но если загрузка происходит, возникает проблема. Я должен сохранить один основной массив, который содержит самописные объекты, называемые Box. Один ящик имеет NSString * boxName и шесть NSMutableArray *, которые содержат другой самописанный объект, называемый Flashcard, который содержит два NSString *: вопрос и ответ. Если AppDelegate получает сообщение applicationWillTerminate, он кодирует основной массив (называемый boxArray) с помощью NSKeyedArchiver и сохраняет его в настройках. В методе init AppControll этот архив загружается из настроек:

- (id)init {
self = [super init];
if (self) {
    // Initialization code here.
    NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
    NSData* archive = [defaults objectForKey:@"boxArray"];
    if (archive) {
        NSArray* array = [NSKeyedUnarchiver unarchiveObjectWithData:archive];
        boxArray = [NSMutableArray arrayWithArray:array];
    } else {
    boxArray = [[NSMutableArray alloc] init];
    }

}

return self;

}

В методе encodeWithCoder для Box он создает несколько объектов NSData * для всех своих массивов, например:

NSData* p1archv = [NSKeyedArchiver archivedDataWithRootObject:phase1];  
[aCoder encodeObject:p1archv forKey:@"phase1"];

и загружает все так: NSData * p1archv = [aDecoder decodeObjectForKey: @ "phase1"];

if (p1archv) {
        NSArray* a = [NSKeyedUnarchiver unarchiveObjectWithData:p1archv];
        phase1 = [NSMutableArray arrayWithArray:a];
        NSLog(@"loaded phase1: %@",phase1);
    } else {
        phase1 = [[NSMutableArray alloc] init];
        NSLog(@"inited phase1");
    }

Сохраняет свое собственное имя коробки, например: [aCoder encodeObject: boxName forKey: @ "boxName"]; Загрузка выглядит так:

 boxName = [aDecoder decodeObjectForKey:@"boxName"];

Карты кодируются с помощью кодера:

- (void) encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeObject:question forKey:@"question"];
[aCoder encodeObject:answer forKey:@"answer"];
NSLog(@"encoded %@ and %@",question, answer);

}

и initWithCoder:

- (id) initWithCoder:(NSCoder *)aDecoder {
self = [super init];
if (self) {
    // Initialization code here.
    question = [aDecoder decodeObjectForKey:@"question"];
    answer = [aDecoder decodeObjectForKey:@"answer"];
}

return self;

}

Хорошо, теперь вы знаете фактическую настройку, но это моя настоящая проблема:

Если приложение запускается и есть настройки для загрузки, оно вылетает в файле Box.h. Чтобы быть точным, он вылетает в этой строке:

@property (readwrite, copy) NSString* boxName;

с EXC_BAD_ACCESS. Я включил NSZombieEnabled, и он показал точно такую ​​же строку. В своих исследованиях я установил точки торможения для каждого метода и выяснил, что в init с методом кодера Box все в порядке, и boxName - это то, что должно быть (например, "foo"), но если tableview (Managed NSArrayController) хочет загрузить данные в табличное представление, которое вылетает во время работы или показывает такие вещи, как, например, «1: 918», шаг за шагом. Я уверен, что я не выпустил массив, имя boxName или что-либо еще в процессе загрузки, поэтому я не могу объяснить эту проблему. Я был бы очень рад, если бы вы могли мне помочь, Elefantosque

1 Ответ

6 голосов
/ 02 июня 2011

Я подозреваю, что ваша проблема в том, что decodeObjectForKey всегда будет возвращать объект с автоматическим освобождением. Поэтому:

boxName = [aDecoder decodeObjectForKey:@"boxName"]; // AUTORELEASED!!!

Вставляет строку в boxName, которая в конечном итоге исчезнет, ​​а затем вы получите уродливый грамм. ТАКЖЕ, определяется как это свойство:

@property (readwrite, copy) NSString* boxName;

Когда я бы использовал:

@property (readwrite, retain) NSString* boxName;

А затем в коде используется следующее:

self.boxName = [aDecoder decodeObjectForKey:@"boxName"]; // HAVE TO USE self.boxName

Что делает, это сохраняет строку в boxName. Я предполагаю, что если вы измените строку свойств и строку назначения, ваша ошибка исчезнет (хотя у вас могут быть другие).

Если вы не хотите менять строку собственности, вы можете использовать:

 [boxName autorelease];                                       // to be on the safe side
 boxName = [[aDecoder decodeObjectForKey:@"boxName"] retain]; // no more uglygram

ПРАВИЛО БАРАБАНА: Если вы не используете [alloc], предположите, что объект автоматически выпущен.

...