Pergunta

Eu tenho uma classe que eu fiz em um singleton e sou capaz de salvá-lo do estado usando um NSKeyedArchiver, mas não posso envolver minha cabeça em torno de puxá-lo de volta estado fora.

Na função que faz o carregamento eu tenho

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

Com esse código, o que faz retorno decodeObjectForKey? Não pode ser realmente outra instância do local e não está carregando em qualquer um dos valores salvos. Antes que eu convertido para uma economia Singleton e carregamento estava funcionando bem.

Foi útil?

Solução

Aqui é onde eu acho que isso está errado. Você está familiarizado com NSCoding e tipicamente adotá-lo, tornando o seu codificável objeto via encodeWithCoder: e initWithCoder: substituições. O que vai fazer tudo isso mais simples é que você ainda pode usar NSCoding e NSCoders sem substituir esses métodos. Você pode codificar o estado do objeto compartilhado sem que codifica a compartilhada obejct si. Isso evita que a questão embaraçosa de decodificar o objeto compartilhado.

Aqui está um exemplo do que eu acho que você poderia fazer:

@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

Aqui temos um objeto compartilhado, e ele usa arquivos com chave de persistir configuração, mas não codificar o próprio objeto compartilhado. Este evitar essa pergunta embaraçosa de decodificar uma segunda instância da classe Singleton.

Outras dicas

Você precisa fazer o carregamento no singleton em si o que está acontecendo aqui é criar o único, você atribuir um lVal ao Singleton, você, em seguida, criar um novo objeto e atribuir novamente a lVal a esse novo objeto sem modificar o singleton . Em outras palavras:

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

O que você quer fazer é lidar com isso no sharedVenue. Há um par de maneiras que as pessoas que singletons, por isso não posso ter certeza que você está fazendo, mas vamos supor sharedVenue atualmente é algo como isto:

static Venue *gSharedVenue = nil;

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

  return gSharedVenue;
}

Assumindo que é o caso de você querer mudá-lo para carregar o objeto para o apoio global 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;
}

Obviamente, você precisa de algum modo transmitir o caminho real para arquivo objeto arquivado.

EDIT base no comentário:

Ok, se você estiver usando o alloc base singleton você precisa lidar com isso nas aulas método 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;
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top