6

Я надеюсь, что это не связано с тем, что я использую Mutable array здесь, но этот меня озадачивает, поэтому меня это не удивит, если бы это было так ,NSKeyedArchiver и NSKeyedUnarchiver с NSMutableArray

ФОН:

Я сделал небольшую базу данных, которая является по существу NSMutableArray, содержащий пользовательские объекты, которую мы можем назвать recordObjects. Я создал массив:

database = [[NSMutableArray alloc] init]; 

и мой пользовательский объект, называемый «recordObject» содержит следующие переменные и inits:

NSString *name; 
int  anInt; 
Bool  aBool; 

Я также синтезируют методы, так что я могу совершать звонки, как:

aString = [[database objectAtIndex:someIndex] name]; 

И добавил методы к классу контроллера для добавления, удаления и выбора отдельных записей для отображения. Пока все работает правильно и точно так, как ожидалось.

Далее я создал свой recordObject класс (подкласс) NSObject использовать NSCoder (путем включения в директиве @interface, и добавлены следующие пользовательские кодер и декодер методов в файле реализации:

-(void) encodeWithCoder: (NSCoder *) encoder { 
    [encoder encodeObject: name forKey: @"recordName"]; 
    [encoder encodeInt: anInt forKey: @"recordInteger"]; 
    [encoder encodeBool: aBool forKey: @"recordBool"]; 
} 

-(id) initWithCoder: (NSCoder *) decoder { 
    name = [decoder decodeObjectForKey: @"recordName"]; 
    anInt = [decoder decodeIntForKey: @"recordInteger"]; 
    aBool = [decoder decodeBoolForKey: @"recordBool"]; 
} 

для того, чтобы написать файл, я использовал следующее:.

[NSKeyedArchiver archiveRootObject:database toFile:myPath]; 

при запуске программы, все ПОЯВЛЯЕТСЯ для корректной работы метод кодировщика вызывается для каждого из записей в массиве и файл записывается на диск. Открытие файла w Ith TextEdit показывает, что данные есть (хотя в основном непонятна мне.)

ПРОБЛЕМА:

Вот где я бегу в корягу.

Я добавил следующий код, чтобы загрузить файл в моем массиве базы данных:

database = [NSKeyedUnarchiver unarchiveObjectWithFile:myPath]; 

Когда я снова запустить программу, на этот раз Загрузка базы данных, он ПОЯВЛЯЕТСЯ работать правильно. Мой первый тест был использовать NSMutableArray метод подсчета:

x = [database count]; 

В результате, X заполняется с правильным количеством записей в файле. Если было сохранено 5 записей, когда я сохранил базу данных, X будет установлен на 5 после загрузки базы данных при следующем выполнении программы.

Теперь вот большая проблема:

Программа вылетает при попытке использовать любой из моих методов доступа.Например, если я пытаюсь использовать следующее после загрузки базы данных:

aString = [[database objectAtIndex:someIndex] name]; 

программные сбои и возвращает следующее сообщение об ошибке в консоли:

Program received signal: “EXC_BAD_ACCESS”. 
sharedlibrary apply-load-rules all 

Моя интерпретация является то, что данные не загружен и инициализирован в массив базы данных по какой-то причине, но для жизни я не могу понять, где я здесь ошибся.

В качестве примечания, все я реализовал пришел из книги Стивена Г. Кочан в «Программирование в Objective-C»

Любые идеи, было бы весьма признателен!

ответ

14

Есть несколько проблем с кодом.

Ваш метод initWithCoder: не выполнен полностью. Вы должны позвонить [super init] и вернуть self. Вы должны также copy или retain объект строки, в противном случае он будет autoreleased:

- (id)initWithCoder:(NSCoder *)decoder 
{ 
    self = [super init]; 
    if(self) 
    { 
     name = [[decoder decodeObjectForKey: @"recordName"] copy]; 
     anInt = [decoder decodeIntForKey: @"recordInteger"]; 
     aBool = [decoder decodeBoolForKey: @"recordBool"]; 
    } 
    return self; 
} 

Другая проблема с этой линии:

database = [NSKeyedUnarchiver unarchiveObjectWithFile:myPath]; 

Это нормально, за исключением двух вещей:

  1. У вас нет ссылки на объект, поэтому он будет автореализован.
  2. NSKeyedArchiver возвращает неизменный объект, в данном случае NSArray, а не NSMutableArray.

Вы должны сделать это:

database = [[NSKeyedUnarchiver unarchiveObjectWithFile:myPath] mutableCopy]; 

Это будет как сохранить объект (потому что это копия) и сделать объект NSMutableArray.

+0

Не хватило бы -copy? Согласно документам, unarchiveObjectWithFile: «возвращает граф объектов, предварительно закодированный NSKeyedArchivier». В этом случае это был NSMutableArray. –

+0

Нет, если вы вызываете 'copy' на' NSMutableArray', тогда вы получите неизменяемый 'NSArray'. К сожалению, здесь документы говорят только половину истории. То же самое происходит с 'NSCoder'. Если вы используете 'NSCoder' для кодирования' NSMutableString', то при его расшифровке вы вернете 'NSString'. Вы должны использовать 'mutableCopy', чтобы вернуть измененные версии. –

+1

Неверный вопрос о архивировании изменяемых объектов. Архивирование и разблокирование изменяемого объекта, такого как 'NSMutableArray' или' NSMutableString', не делает его неизменным. –

2

Звучит как проблема управления памятью для меня. EXC_BAD_ACCESS обычно означает, что вы пытаетесь получить доступ к объекту, который был освобожден. unarchiveObjectWithFile: возвращает автореализованный объект, поэтому вам нужно сохранить его, если вы хотите его сохранить, либо с явным retain, либо назначив его сохраненному свойству.

+0

Hm. Это объяснило бы это (я в настоящее время ЧУВСТВИТЕЛЬНО плохо с управлением памятью в этот момент ... все еще пытаюсь обдумать его.) –

+0

На основании приведенного выше кода вы видите или можете рекомендовать способ сохранения базы данных массив? Я снова перечитаю главу «Управление памятью» сегодня вечером и посмотрю, смогу ли я это выяснить, но если есть простое исправление, мы будем очень благодарны! :) –

+0

Я должен упомянуть, что я использую Xcode 3.2.6 на OSX 10.6.8 –

4

Это не кажется, что вы инициализации recordObjects в -initWithCoder:

Попробуйте что-то вроде этого:

-(id) initWithCoder: (NSCoder *) decoder { 

    self = [super init]; 

    if (self){ 

     name = [decoder decodeObjectForKey: @"recordName"] copy]; 
     anInt = [decoder decodeIntForKey: @"recordInteger"]; 
     aBool = [decoder decodeBoolForKey: @"recordBool"]; 
    } 

    return self; 
} 

данные там, когда вы архивировать его, но вы не правильно разборки.

+0

Я дам этот снимок и отчитаюсь. Благодарю. –

+0

Важная часть состоит в том, что это предложение заканчивается «возвращением себя». Вам этого не хватает. Кроме того, требуется вызов суперинтеграции. –

+0

Нехорошо. Я даже пытался использовать [[super alloc] init]; но все же дает ту же ошибку. –

0

У меня была такая же проблема, когда разархивировав пользовательский объект

self.calTable = [[NSKeyedUnarchiver unarchiveObjectWithFile:calibrationFile] objectForKey:@"calTable"]; 

На основании ответа Роба я изменил

self.calTable = [[[NSKeyedUnarchiver unarchiveObjectWithFile:calibrationFile] mutableCopy] objectForKey:@"calTable"]; 

и исправлены все ошибки.

 Смежные вопросы

  • Нет связанных вопросов^_^