2009-07-18 10 views
7

私はシングルトンにしてNSKeyedArchiverを使ってその状態を保存することができるクラスを持っていますが、私は元の状態を取り戻すことはできません。私はこのコードでは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の別のインスタンスではありません。保存された値のいずれにもロードされていません。私はそれをシングルトンの保存に変換する前に、読み込みは正常に動作していました。

答えて

8

です。あなたはNSCodingに精通しており、通常、オブジェクトをencodeWithCoder:およびinitWithCoder:overridesを介してコード化可能にすることで採用しています。これをもっと簡単にするのは、これらのメソッドをオーバーライドせずに、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番目のインスタンスをデコードするという面倒な問題を避けることができます。

+0

この答えは、私がそれの周りに私の頭を包むことができるのでちょうど私にはちょっと意味があります。もう一方のinitは正しく見えますが、概念化するのは少し難しいです。 – rob5408

+0

偉大な答え...ちょうど参考に誰かがこの質問につまずいた場合、私はinitメソッドは、NSKeyedUnarchiverを使用する必要がありますと信じています。 – Bern11

+0

ありがとう、スニペットを更新しました。 –

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

明らかに、何らかの形でアーカイブされたオブジェクト・ファイルへの実際のパスを伝える必要があります。

EDIT COMMENTに基づく:

さて、あなたはアロケーションベースのシングルトンを使用している場合は、クラスでこの問題に対処する必要があるメソッド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

私はそれを理解していると思います。試してみましょう。 シングルトンを実装する方法については、この男のマクロを使用しています。これはかなり素晴らしいです:http://cocoawithlove.com/2008/11/singletons-appdelegates-and-top-level.html – rob5408

+0

異なるパターンを使用する場合は、これをあなたのシングルトンのinitメソッドで処理する必要があります。私はあなたが答えにどのようにこれを行うかを追加しています –

関連する問題