Question

J'ai une classe que je l'ai fait dans un singleton et je suis en mesure de sauver son état à l'aide d'un NSKeyedArchiver, mais je ne peux pas envelopper la tête autour tirant son état arrière.

Dans la fonction qui fait la charge que j'ai

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

Avec ce code, ce qui ne retourne decodeObjectForKey? Il ne peut pas vraiment être une autre instance de lieu et il ne se charge pas dans l'une des valeurs enregistrées. Avant que je converti à une économie singleton et le chargement était bien travailler.

Était-ce utile?

La solution

est ici où je pense que cela va mal. Vous êtes familier avec NSCoding et en adoptant généralement en faisant de votre détrompable objet via encodeWithCoder: et initWithCoder: overrides. Que va faire tout cela plus simple est que vous pouvez toujours utiliser NSCoding et NSCoders sans écraser ces méthodes. Vous pouvez coder l'état de l'objet partagé sans coder le obejct partagé lui-même. Cela évite la question délicate de décoder l'objet partagé.

Voici un exemple de ce que je pense que vous pourriez faire:

@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

Ici, nous avons un objet partagé, et il utilise des archives claveté persister la configuration, mais nous ne chiffrons pas l'objet partagé lui-même. Cela permet d'éviter cette question délicate de décodage d'une deuxième instance de la classe singleton.

Autres conseils

Vous devez faire le chargement dans le singleton lui-même ce qui se passe ici est que vous créez le seul, vous attribuez un LVAL au singleton, vous créez ensuite un nouvel objet et réattribuer la LVAL à ce nouvel objet sans modifier le singleton . En d'autres termes:

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

Qu'est-ce que vous voulez faire est affaire avec cela dans le sharedVenue. Il y a deux façons dont les gens font singletons, donc je ne peux pas être sûr de ce que vous faites, mais laisse supposer sharedVenue ressemble actuellement quelque chose comme ceci:

static Venue *gSharedVenue = nil;

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

  return gSharedVenue;
}

En supposant que cela est le cas que vous voulez changer pour charger l'objet dans le support 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;
}

Il est évident que vous devez transmettre en quelque sorte le chemin réel vers le fichier objet archivé.

EDIT BASÉ SUR UN COMMENTAIRE:

D'accord, si vous utilisez le singleton à base alloc dont vous avez besoin pour faire face à cela dans la méthode init classes:

- (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;
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top