7

シングルトンにしたクラスがあり、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 の別のインスタンスになることはできず、保存された値のいずれにも読み込まれていません。シングルトンの保存と読み込みに変換する前は、正常に機能していました。

4

2 に答える 2

8

ここが間違っていると思うところです。あなたは NSCoding に精通しており、通常は、encodeWithCoder: および initWithCoder: オーバーライドを介してオブジェクトをコーディング可能にすることで、NSCoding を採用しています。これをすべて簡単にするのは、これらのメソッドをオーバーライドせずに 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

ここに共有オブジェクトがあり、キー付きアーカイブを使用して構成を保持しますが、共有オブジェクト自体はエンコードしません。これにより、シングルトン クラスの 2 番目のインスタンスをデコードするという厄介な問題が回避されます。

于 2009-07-20T01:35:12.600 に答える
3

シングルトン自体でロードを行う必要があります。ここで行われているのは、シングルを作成し、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;
}
于 2009-07-18T23:30:10.147 に答える