Приложението се срива (EXC_BAD_ACCESS) при зареждане на Предпочитания на @Property

това е един от многото 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, той създава sereval 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 и той показа точно същия ред. По време на моето проучване направих спирачни точки за всеки отделен метод и открих, че в метода init with coder на Box всичко е наред и boxName е това, което трябва да бъде (напр. "foo"), но ако tableview (Managed от NSArrayController) иска да зареди данните в табличния изглед, в който се срива, докато работи, или показва неща като напр. "1:918" при преминаване през отделните стъпки. Сигурен съм, че не съм освободил масива, или boxName, или каквото и да било преди в процеса на зареждане, така че не мога да обясня този проблем. Ще се радвам, ако можете да ми помогнете, Elefantosque


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