Сохранение пользовательских объектов

У меня есть пользовательский объект, который просто наследуется от NSObject. Он имеет 3 члена - два поплавка и NSDate.

Мое приложение будет иметь массив с рядом этих объектов, ногами, и мне нужно сохранить его между прогонами. Как я могу это сделать?

Я думал об использовании SQLite db, но я думаю, что это немного перебор, так как единственный запрос, который я когда-либо делал, был бы select *.

В идеальном мире я бы хотел использовать файл xml plist. Я не уверен, могу ли я сделать это с помощью своего пользовательского объекта. Я знаю, что существует набор объектов Property List, и что NSArray подпадает под это, но writeToFile:atomically: работает только с объектами списка свойств.

Любые мысли будут оценены, спасибо!

Ответ 1

NSCoding сделает именно то, что вы хотите. Я рекомендую вам прочитать его в документах Apple, но я подумал, что это довольно просто использовать. Ваш класс (и любые дочерние классы) должен будет реализовать протокол NSCoding, и вам нужно будет добавить методы -encodeWithCoder: и -initWithCoder: к вашим объектам. Большинство классов общих классов уже реализуют NSCoding.

Код для вашего класса будет выглядеть примерно так:

-(void) encodeWithCoder: (NSCoder*) coder {
  [coder encodeInteger: versionValue forKey: versionKey];
  [coder encodeObject: myStuff forKey: myStuffKey];
}

-(id) initWithCoder: (NSCoder*) coder {
  self = [super init];
  if ( ! self) return nil;
  myStuff = [[coder decodeObjectForKey: myStuffKey] retain];
  return self;
}

Он рекомендовал вам добавить номер версии при кодировании, чтобы предоставить вам гибкость для управления изменениями в вашем формате архива в будущих версиях.

В моем классе я добавил метод удобства для архивирования моего объекта:

-(void) archiveToFile: (NSString*) path {
  NSMutableData *data = [[NSMutableData alloc] init];
  NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData: data];
  [archiver encodeObject: self forKey: myArchiveKey];
  [archiver finishEncoding];
  [archiver release];
  [data writeToFile: path atomically: YES];
  [data release];
}

а другой - для разблокировки или создания нового объекта:

+(MyArchive*) newFromFile: (NSString*) path
            orWithMyStuff: (MyStuff*) myStuff
{
  NSData *data = [[NSData alloc] initWithContentsOfFile: path];
  NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData: data];
  MyArchive *myArchive = [unarchiver decodeObjectForKey: myArchiveKey];
  [unarchiver finishDecoding];

  if (myArchive) {
    [myArchive retain];
  } else {
    myArchive = [[MyArchive alloc] initWithStuff: myStuff;
  }
  [unarchiver release];
  [data release];
  return myArchive;
}

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

Ответ 2

Если вы захотите получить подмножество объектов, SQLite, безусловно, ваш лучший выбор.

Если нет, это выбор между форматом plist и NSCoding. plist требует, чтобы вы могли конвертировать ваши пользовательские объекты в нечто дружелюбное к plist, а затем преобразовывать plist обратно в ваши объекты, но NSCoding немного сложнее обернуть вокруг вас и не может быть легко отредактирован (или проверен) вручную.