3

私は基本的なゲームを書いてGameStateManagerいます。シングルトンであり、保存、読み込み、削除メソッドなどのすべての状態管理を処理する を使用しています。

私はすべてのGameものを処理する別のシングルトンを持っています。ゲーム オブジェクトはゲーム ステート マネージャー内にあるため、NSCoding とアーカイブを使用して保存できます。

状態を保存すると、問題はないように見え、Game オブジェクト (シングルトン) は適切に保存されます。

ただし、(アプリを再起動して) 状態を読み込もうとすると、ゲーム オブジェクトは常に null になります。

Strangley、シングルトン プロパティを削除して標準クラスにすると、この問題は解消され、大きな問題なくクラスとそのすべてのプロパティをロードできます。

要約すると、私はこれを行います:

  1. GameStateManager = Singleton、すべてのゲーム状態管理 (ロード、保存) を処理し、ゲーム オブジェクト (ゲーム) を持ちます

  2. Game = ゲーム内の処理を行うシングルトンであり、NSCoding プロトコルが採用されています。

  3. ゲームオブジェクトでゲームの状態を保存することは問題ありません。オブジェクトは明らかにそこにあります。

  4. ゲーム ステートをロードすると、ゲーム オブジェクトが null になるようです。そこにあるはずですが、何らかの理由でロードされません。

  5. ゲームクラスをシングルトンにするすべてのプロパティを削除して通常のクラスにすると、問題は解決するようです。

決して初期化されないという事実と関係があると思いますGameが、シングルトン プロパティがないときにゲームをロードできるため、これは意味がありません。

コードは次のとおりです。

// GameStateManager.m

-(void)saveGameState
{
    CCLOG(@"METHOD: saveGameState()");

    self.lastSaveDate   = [NSDate date];

    NSMutableData *data;
    NSString *archivePath = [NSTemporaryDirectory() stringByAppendingPathComponent:kGameSaveFile];
    NSKeyedArchiver *archiver;
    BOOL result;

    data = [NSMutableData data];
    archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];

    [archiver encodeObject:self.lastSaveDate forKey:@"lastSaveDate"];
    [archiver encodeObject:self.game forKey:@"game"];
    [archiver finishEncoding];
    result = [data writeToFile:archivePath atomically:YES];
    [archiver release];

}

-(void)loadGameState
{
    CCLOG(@"METHOD: loadGameState()");


    NSData *data;
    NSKeyedUnarchiver *unarchiver;
    NSString *archivePath = [NSTemporaryDirectory() stringByAppendingPathComponent:kGameSaveFile];

    data = [NSData dataWithContentsOfFile:archivePath];
    unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];

    // Customize unarchiver here
    self.game = [unarchiver decodeObjectForKey:@"game"];
    self.lastSaveDate = [unarchiver decodeObjectForKey:@"lastSaveDate"];

    [unarchiver finishDecoding];
    [unarchiver release];


    CCLOG(@"Last Save Date = %@", self.lastSaveDate);
    NSLog(@"game = %@", self.game);
}

// END OF GAMESTATEMANAGER

// -------------------------

 // Game.h
    @interface Game : NSObject
<NSCoding>
{
    NSMutableArray *listOfCities;
    NSMutableArray *listOfColors;
    NSMutableArray *listOfPlayers;
}

@property (nonatomic, retain) NSMutableArray *listOfCities;
@property (nonatomic, retain) NSMutableArray *listOfColors;
@property (nonatomic, retain) NSMutableArray *listOfPlayers;

+(Game *) sharedGame;


 //
// Game.m
// This is a cut-down version of the game object
// Game is a singelton
// The listOfCities, etc are arrays
//
@implementation Game
SYNTHESIZE_SINGLETON_FOR_CLASS(Game)
@synthesize listOfCities, listOfPlayers;

#pragma mark - NSCoding


-(id)initWithCoder:(NSCoder *)aDecoder
{
    self = [super init];

    if (self) 
    {
        self.listOfCities = [aDecoder decodeObjectForKey:@"listOfCities"];
        self.listOfPlayers = [aDecoder decodeObjectForKey:@"listOfPlayers"];

        NSLog(@"Cities = %d", [self.listOfCities count]);
        NSLog(@"Players = %d", [self.listOfPlayers count]);
    }

    return self;
}

-(void)encodeWithCoder:(NSCoder *)aCoder
{
    // Archive objects
    NSLog(@"Cities = %d", [self.listOfCities count]);
    NSLog(@"Players = %d", [self.listOfPlayers count]);

    [aCoder encodeObject:self.listOfCities forKey:@"listOfCities"];
    [aCoder encodeObject:self.listOfPlayers forKey:@"listOfPlayers"];
}

@end

私の質問は、NSCoding とアーカイバを使用して、Objective C シングルトンを正常に保存およびロードするにはどうすればよいですか?

編集;

私が試してみました:

// In the GameStateManager
#pragma mark - NSCoding

-(id)initWithCoder:(NSCoder *)decoder {
    if (self = [super init]) {
        self.lastSaveDate = [[decoder decodeObjectForKey:@"lastSaveDate"] retain];
        self.game = [[decoder decodeObjectForKey:@"game"] retain];
    }
    return self;
}
-(void)encodeWithCoder:(NSCoder *)encoder {
    [encoder encodeObject:self.lastSaveDate forKey:@"lastSaveDate"];
    [encoder encodeObject:self.game forKey:@"game"];
}

// In Game.m
    self.listOfCities = [[aDecoder decodeObjectForKey:@"listOfCities"] retain];
        self.listOfPlayers = [[aDecoder decodeObjectForKey:@"listOfPlayers"] retain];

        NSLog(@"Cities = %d", [self.listOfCities count]);
        NSLog(@"Players = %d", [self.listOfPlayers count]);
4

4 に答える 4

6

シングルトンを扱っているので、いつでもクラスの単一のインスタンスだけが存在することを望んでいます。そのため、その単一のインスタンスのみをアーカイブおよびアーカイブ解除する必要があります。

次のコードを検討してください (ARC が有効になっていると仮定します)。

@interface Singleton : NSObject <NSCoding>

+ (id)sharedInstance;
@property (strong, nonatomic) NSString *someString;

@end

@implementation Singleton

+ (id)sharedInstance {
    static Singleton instance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[Singleton alloc] init];
    });
    return instance;
}

#pragma mark - NSCoding implementation for singleton

- (id)initWithCoder:(NSCoder *)aDecoder {
    // Unarchive the singleton instance.
    Singleton *instance = [Singleton sharedInstance];

    [instance setSomeString:[aDecoder decodeObjectForKey:@"someStringKey"]];

    return instance;
}

- (void)encodeWithCoder:(NSCoder *)aCoder {
    // Archive the singleton instance.
    Singleton *instance = [Singleton sharedInstance];

    [aCoder encodeObject:[instance someString] forKey:@"someStringKey"]];
}

@end

このテンプレートを使用すると、次のようにシングルトンをアーカイブ/アーカイブ解除できます。

// Archiving calls encodeWithCoder: on the singleton instance.
[[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:[Singleton sharedInstance]] forKey:@"key"];

// Unarchiving calls initWithCoder: on the singleton instance.
[[NSKeyedUnarchiver unarchiveObjectWithData:[[NSUserDefaults standardUserDefaults] objectForKey:@"key"]];
于 2012-10-10T17:41:52.670 に答える
1

initWithCoderメソッドでこれを試してください:

self.listOfCities = [[aDecoder decodeObjectForKey:@"listOfCities"] retain];
self.listOfPlayers = [[aDecoder decodeObjectForKey:@"listOfPlayers"] retain];
于 2012-07-14T13:36:22.787 に答える