2009-07-18 2 views
7

У меня есть класс, который я сделал в одноэлементном режиме и могу сохранить его состояние с помощью NSKeyedArchiver, но я не могу обернуть голову, вытащив его состояние.Загрузка состояния Singleton из 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 вернуться? Это не может быть другим экземпляром места, и он не загружается ни в одну из сохраненных значений. До того, как я преобразовал его в одноэлементное сохранение и загрузка работала нормально.

ответ

8

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

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

@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 

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

+0

Этот ответ имеет для меня немного больше смысла, просто потому, что я могу обвести вокруг него голову. Инициирование другого кажется правильным, но немного сложнее концептуализировать. – rob5408

+0

Отличный ответ ... просто FYI на случай, если кто-то наткнутся на этот вопрос, я считаю, что метод init должен использовать NSKeyedUnarchiver. – Bern11

+0

Спасибо, обновил фрагмент. –

3

Вам нужно сделать загрузку в одиночном одиночном режиме, что здесь происходит, вы создаете сингл, вы назначаете lval для singleton, затем создаете новый объект и переназначаете 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; 
} 

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

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

Хорошо, если вы используете Alloc на основе одноплодной вы должны иметь дело с этим в классах инициализации метод:

- (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; 
} 
+0

Хорошо, я понимаю, что понимаю, позвольте мне попробовать. Что касается того, как я реализую свой синглтон, я использую макрос этого парня, который является довольно устрашающим: http://cocoawithlove.com/2008/11/singletons-appdelegates-and-top-level.html – rob5408

+0

Он использует другой шаблон, вам нужно обработать это в методе inittesons init. Вам нужно сделать одну сложную вещь, которая возвращает не-супер вещь, я добавляю, как вы это делаете с ответом –

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