2009-07-18 11 views
7

Mam klasę, którą stworzyłem w singletonie i jestem w stanie zapisać jej stan za pomocą NSKeyedArchiver, ale nie mogę objąć głowy, wyciągając stan z powrotem.Ładowanie stanu Singletona z NSKeyedArchiver

W funkcji, dokłada ładowanie mam

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

Z tym kodem, co robi decodeObjectForKey powrócić? To naprawdę nie może być kolejna instancja Miejsca i nie ładuje się w żadnej z zapisanych wartości. Zanim przekonwertowałem go do trybu pojedynczego, zapisywanie i ładowanie działało poprawnie.

Odpowiedz

8

Oto, gdzie myślę, że to będzie źle . Znasz NSCoding i zazwyczaj go adoptujesz, czyniąc obiekt kodowalnym za pomocą encodeWithCoder: i initWithCoder: przesłonięcie. Wszystko to uprości to, że nadal można używać NSCoding i NSCoderów bez nadpisywania tych metod. Można zakodować stan obiektu współdzielonego bez kodowania samej udostępnionej obejści. Zapobiega to niezręcznej kwestii dekodowania obiektu współdzielonego.

Oto przykład tego, co myślę, że można zrobić:

@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 

Tutaj mamy wspólny cel, i korzysta z kluczykiem archiwum utrzymują konfigurację, ale nie kodują udostępniony sam obiekt. To pozwala uniknąć tej niezręcznej kwestii dekodowania drugiej instancji klasy singleton.

+0

Ta odpowiedź ma dla mnie trochę więcej sensu, tylko dlatego, że mogę ją owinąć. Inicjatywa tego drugiego wydaje się poprawna, ale nieco trudniejsza do konceptualizacji. – rob5408

+0

Świetna odpowiedź ... po prostu FYI na wypadek, gdyby ktoś natknął się na to pytanie, uważam, że metoda init powinna używać NSKeyedUnarchiver. – Bern11

+0

Dzięki, zaktualizowałeś fragment. –

3

Musisz wykonać ładowanie w samym singletonie, co się tutaj dzieje, to tworzysz singiel, przypisujesz lval do singletonu, następnie tworzysz nowy obiekt i ponownie przypisujesz lval do tego nowego obiektu BEZ modyfikowania singel. Innymi słowy:

//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]; 

To, co chcesz zrobić, to uporać się z opcją sharedVenue. Istnieje kilka sposobów zrobienia pojedynczych osób, więc nie mogę być pewien, co robisz, ale pozwala zakładać sharedVenue obecnie wygląda mniej więcej tak:

static Venue *gSharedVenue = nil; 

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

    return gSharedVenue; 
} 

Zakładając, że ma miejsce w przypadku chcesz go zmienić załadować obiekt w globalnej podkładzie singleton:

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; 
} 

Oczywiście trzeba jakoś przekazać rzeczywistą ścieżkę do archiwum pliku wynikowego.

EDIT oparte na komentarz:

Dobrze, jeśli używasz singleton oparte na Alloc trzeba sobie z tym poradzić w klasach metody 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; 
} 
+0

OK, myślę, że rozumiem to, pozwól mi spróbować. Jeśli chodzi o sposób, w jaki realizuję swój singleton, używam makra tego faceta, który jest niesamowity: http://cocoawithlove.com/2008/11/singletons-appdelegates-and-top-level.html – rob5408

+0

On używa innego wzorca, musisz to obsłużyć w swojej inicjalizacji singleton. Musisz zrobić jedną trudną rzecz, która jest zwrotem niezbyt ciekawym, dołączam, jak to robisz, aby odpowiedzieć na tę odpowiedź. –

Powiązane problemy