Загрузка состояния синглтона из NSKeyedArchiver

У меня есть класс, который я превратил в одноэлементный файл, и я могу сохранить его состояние с помощью NSKeyedArchiver, но я не могу обернуть голову, вытаскивая его состояние обратно.

В функции, которая делает загрузку у меня

Venue *venue = [Venue sharedVenue];
NSData *data = [[NSMutableData alloc] initWithContentsOfFile:[self dataFilePath]];
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
venue = [unarchiver decodeObjectForKey:@"Venue"];
[unarchiver finishDecoding];

С этим кодом, что возвращает decodeObjectForKey? Это действительно не может быть другим экземпляром Venue, и он не загружается ни в одно из сохраненных значений. До того, как я преобразовал его в синглтон, сохранение и загрузка работали нормально.

Ответы на вопрос(2)

Вам нужно выполнить загрузку в самом синглтоне, что происходит здесь: вы создаете сингл, назначаете lval для синглтона, затем создаете новый объект и переназначаете lval этому новому объекту БЕЗ модификации синглтона. Другими словами:

//Set venue to point to singleton
Venue *venue = [Venue sharedVenue];

//Set venue2 to point to singleton
Venue *venue2 = [Venue sharedVenue];

NSData *data = [[NSMutableData alloc] initWithContentsOfFile:[self dataFilePath]];
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];

//Set venue to unarchived object (does not change the singleton or venue2)
venue = [unarchiver decodeObjectForKey:@"Venue"];
[unarchiver finishDecoding];

То, что вы хотите сделать, это разобраться с этим в sharedVenue. Есть несколько способов, которыми люди делают синглтоны, поэтому я не могу быть уверен, что вы делаете, но давайте предположим, что sharedVenue в настоящее время выглядит примерно так:

static Venue *gSharedVenue = nil;

- (Venue *) sharedVenue {
  if (!gSharedVenue) {
    gSharedVenue = [[Venue alloc] init];
  }

  return gSharedVenue;
}

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

static Venue *gSharedVenue = nil;

- (Venue *) sharedVenue {
  if (!gSharedVenue) {
    NSData *data = [[NSMutableData alloc] initWithContentsOfFile:[self dataFilePath]];
    NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
    [data release];

    gSharedVenue = [unarchiver decodeObjectForKey:@"Venue"];
    [unarchiver finishDecoding];
    [unarchiver release];
  }

  if (!gSharedVenue) {
    gSharedVenue = [[Venue alloc] init];
  }

  return gSharedVenue;
}

Очевидно, вам нужно как-то передать фактический путь к архивному объектному файлу.

РЕДАКТИРОВАТЬ НА ОСНОВЕ КОММЕНТАРИИ:

Хорошо, если вы используете синглтон на основе alloc, вам нужно разобраться с этим в методе init классов:

- (id) init {
  self = [super init];

  if (self) {
    NSData *data = [[NSMutableData alloc] initWithContentsOfFile:[self dataFilePath]];
    NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
    [data release];

    Venue *storedVenue = [unarchiver decodeObjectForKey:@"Venue"];
    [unarchiver finishDecoding];
    [unarchiver release];

    if (storeVenue) {
       [self release];
       self = [storedVenue retain];
    }

  }

  return self;
}
 rob540819 июл. 2009 г., 01:50
Хорошо, я думаю, что понимаю это, позвольте мне попробовать. Что касается того, как я реализую свой синглтон, я использую макрос этого парня, который довольно хорош:cocoawithlove.com/2008/11/…
 19 июл. 2009 г., 01:59
Он использует другой шаблон, вам нужно справиться с этим в вашем методе init синглетонов. Вы должны сделать одну сложную вещь, которая возвращает не супер вещь, я добавляю, как вы делаете это к ответу
Решение Вопроса

Здесь я думаю, что все идет не так. Вы знакомы с NSCoding и обычно принимаете его, делая свой объект кодируемым с помощью переопределений encodeWithCoder: и initWithCoder:. Все это упростит то, что вы все еще можете использовать NSCoding и NSCoders без переопределения этих методов. Вы можете кодировать состояние общего объекта, не кодируя сам общий объект. Это предотвращает неловкий вопрос декодирования общего объекта.

Вот пример того, что, я думаю, вы могли бы сделать:

@implementation MySharedObject
+ (id)sharedInstance {
    static id sharedInstance = nil;
    if (!sharedInstance) {
        sharedInstance = [[MyClass alloc] init];
    }
}

- (id)init {
    if ((self = [super init])) {
        NSData *data = /* probably from user defaults */
        if (data) { // Might not have any initial state.
            NSKeyedUnarchiver *coder = [[[NSKeyedUnarchiver alloc] initForReadingWithData:data] autorelease];
            myBoolean = [coder decodeBoolForKey:@"MyBoolean"];
            myObject = [[coder decodeObjectForKey:@"MyObject"] retain];
            [coder finishDecoding];
        }
    }
    return self;
}

- (void)saveState {
    NSMutableData *data = [NSMutableData data];
    NSKeyedArchiver *coder = [[[NSKeyedArchiver alloc] initForWritingWithMutableData:data] autorelease];
    [coder encodeBool:myBoolean forKey:@"MyBoolean"];
    [coder encodeObject:myObject forKey:@"MyObject"];
    [coder finishEncoding]
    // Save the data somewhere, probably user defaults...   
}
@end

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

 24 дек. 2012 г., 11:21
Спасибо, обновил фрагмент.
 24 дек. 2012 г., 01:56
Отличный ответ ... просто к сведению, если кто-то наткнется на этот вопрос, я считаю, что метод init должен использовать NSKeyedUnarchiver
 rob540821 июл. 2009 г., 18:20
Этот ответ имеет для меня больше смысла, просто потому, что я могу обернуть голову вокруг него. Другой init кажется правильным, но его немного сложнее осмыслить.

Ваш ответ на вопрос