Pergunta

I have written the following method to encode/decode data..

- (void) encode: (BOOL) encodeBool int: (NSNumber *) integer boolean:(BOOL) boolean key: (NSString *) keyStr {

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *gameStatePath = [documentsDirectory stringByAppendingPathComponent:@"gameData"];



    if (encodeBool == YES) {

        NSMutableData *gameData = [NSMutableData data];
        NSKeyedArchiver *encoder = [[NSKeyedArchiver alloc] initForWritingWithMutableData:gameData];

        if (integer) {
            [encoder encodeInt:[integer intValue] forKey:keyStr];
        }
        else if (boolean) {
            [encoder encodeBool:boolean forKey:keyStr];
        }

        [encoder finishEncoding];
        [gameData writeToFile:gameStatePath atomically:YES];
        [encoder release];


    } else {

        NSMutableData *gameData = [NSData dataWithContentsOfFile:gameStatePath];

        if (gameData) {

            NSKeyedUnarchiver *decoder = [[NSKeyedUnarchiver alloc] initForReadingWithData:gameData];

            if (integer) {
                NSLog(@"%d", [decoder decodeIntForKey:keyStr]);
            }
            else if (boolean) {

                if ([decoder decodeBoolForKey:keyStr]==YES) {
                    NSLog(@"YES");

                } else {
                    NSLog(@"NO");
                }

            }



            [decoder finishDecoding];
            [decoder release];

        }


    }



}

And some testing

    [[GameData sharedData] encode:YES int: [NSNumber numberWithInt:100] boolean:NO key:@"testInt"];
    [[GameData sharedData] encode:YES int:nil boolean:YES key:@"bool"];        
    [[GameData sharedData] encode:YES int:[NSNumber numberWithInt:1030] boolean:nil key:@"test"];

    [[GameData sharedData] encode:NO int: [NSNumber numberWithInt:1]  boolean:nil key:@"testInt"];
    [[GameData sharedData] encode:NO int:nil boolean:YES key:@"bool"];
    [[GameData sharedData] encode:NO int:[NSNumber numberWithInt:100]  boolean:nil key:@"test"];

and output is

0
NO
1030

only the last one is correct.. Can someone tell me what I am doing wrong? Thanks

Foi útil?

Solução

Your problem is that every time you call your method, you overwrite the file - erasing the values you encoded in previous calls. You should probably rewrite your method so that you encode all the values in a single call.

One alternative is to create a GameState object and have it implement NSCoding, then read and serialize it with +[NSKeyedArchiver archiveRootObject:toFile:] and deserialize it with +[NSKeyedUnarchiver unarchiveObjectWithFile:]. The code to do so looks a bit like this:

@interface GameState : NSObject <NSCoding>

@property (nonatomic) int someInt;
@property (nonatomic) BOOL someBool;
@property (nonatomic, strong) NSString *someString;

@end

static NSString *const BoolKey = @"BoolKey";
static NSString *const StringKey = @"StringKey";
static NSString *const IntKey = @"IntKey";

@implementation GameState

- (id)initWithCoder:(NSCoder *)coder
{
    self = [super init];
    if (self) {
        _someBool = [coder decodeBoolForKey:BoolKey];
        _someInt = [coder decodeIntForKey:IntKey];
        _someString = [coder decodeObjectForKey:StringKey];
    }
    return self;
}

- (void)encodeWithCoder:(NSCoder *)aCoder
{
    [aCoder encodeBool:self.someBool forKey:BoolKey];
    [aCoder encodeInt:self.someInt forKey:IntKey];
    [aCoder encodeObject:self.someString forKey:StringKey];
}

@end

//  Somewhere in your app where reading and saving game state is needed...
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = nil;
if ([paths count]) {
    documentsDirectory = paths[0];
}
NSString *archivePath = [documentsDirectory stringByAppendingPathComponent:@"archive"];
GameState *gameState = [NSKeyedUnarchiver unarchiveObjectWithFile:archivePath];
if (!gameState) {
    gameState = [[GameState alloc] init];
    gameState.someString = @"a string";
    gameState.someInt = 42;
    gameState.someBool = YES;
}

//  Make changes to gameState here...

[NSKeyedArchiver archiveRootObject:gameState toFile:archivePath];

Outras dicas

The first problem is when you test if (boolean) it's the same as saying if (boolean == YES). Bools aren't objects, and can't be nil. When you pass nil in as a bool, it's the same as passing NO in. I don't think this accounts for all of your issues though. I think the file is not saving as well.

From the NSKeyedUnarchiver docs:

If you invoke one of the decode... methods of this class using a key that does not exist in the archive, a non-positive value is returned. This value varies by decoded type. For example, if a key does not exist in an archive, decodeBoolForKey: returns NO, decodeIntForKey: returns 0, and decodeObjectForKey: returns nil.

These are the erroneous values you're getting. To start, I note that you're not doing any error checking. Try adding some checks to see what's failing, for example, you could try:

    [encoder finishEncoding];
    NSError *error;
    BOOL success = [gameData writeToFile:gameStatePath options:NSDataWritingAtomic error:&error];
    if (success == NO) NSLog(@"Error: %@", [error localizedDescription]);

Once you get an error, we can go from there.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top