Сбой приложения (EXC_BAD_ACCESS) при загрузке настроек на @Property

это один из многих вопросов EXC_BADACCES, но я долгое время проводил исследования и думаю, что на этот вопрос еще нет ответа. Мое приложение сохраняет данные в настройках. Все прошло хорошо, если я удалю настройки и запущу приложение, чтобы вообще не было загрузки. Но если происходит загрузка, возникает проблема. Мне нужно сохранить один основной массив, который содержит самописные объекты с именем Box. Один Box имеет NSString* boxName и шесть NSMutableArray*, которые содержат еще один самописный объект, называемый Flashcard, который содержит два NSString*: вопрос и ответ. Если AppDelegate получает сообщение applicationWillTerminate, он кодирует основной массив (называемый boxArray) с помощью NSKeyedArchiver и сохраняет его в настройках. В методе инициализации 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"];

Карточки encodeWithCoder:

- (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, и он показал точно такую ​​же строку. В своем исследовании я делал точки останова для каждого метода и обнаружил, что в методе инициализации с кодером Box все в порядке, и boxName - это то, что должно быть (например, "foo"), но если табличное представление (управляемое с помощью NSArrayController) хочет загрузить данные в табличное представление, которое падает во время работы или показывает такие вещи, как, например, «1:918» при пошаговом выполнении отдельных шагов. Я уверен, что не освобождал ни массив, ни boxName, ни что-то еще в процессе загрузки, поэтому я не могу объяснить эту проблему. Я был бы очень рад, если бы вы могли мне помочь, Элефантоск


person Elefantosque    schedule 29.05.2011    source источник


Ответы (1)


Я подозреваю, что ваша проблема заключается в том, что 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], предполагается, что объект освобождается автоматически.

person Feloneous Cat    schedule 02.06.2011