【问题标题】:NSCoding -decoder returns wrong values -iOSNSCoding -decoder 返回错误值 -iOS
【发布时间】:2013-02-25 04:11:51
【问题描述】:

我已经编写了以下方法来编码/解码数据..

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

        }


    }



}

还有一些测试

    [[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"];

输出是

0
NO
1030

只有最后一个是正确的。有人可以告诉我我做错了什么吗?谢谢

【问题讨论】:

    标签: ios objective-c nskeyedarchiver nscoding


    【解决方案1】:

    您的问题是,每次调用方法时,都会覆盖文件 - 删除您在之前调用中编码的值。您可能应该重写您的方法,以便在一次调用中编码所有值。

    另一种方法是创建一个GameState 对象并让它实现NSCoding,然后用+[NSKeyedArchiver archiveRootObject:toFile:] 读取和序列化它,然后用+[NSKeyedUnarchiver unarchiveObjectWithFile:] 反序列化它。这样做的代码看起来有点像这样:

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

    【讨论】:

      【解决方案2】:

      第一个问题是当您测试if (boolean) 时,它与说if (boolean == YES) 相同。布尔不是对象,也不能是nil。当您将nil 作为布尔值传入时,它与将NO 传入相同。我认为这并不能解决您的所有问题。我认为文件也没有保存。

      来自 NSKeyedUnarchiver 文档:

      如果您使用键调用此类的解码...方法之一 存档中不存在的,则返回非正值。 该值因解码类型而异。例如,如果一个键没有 存在于档案中,decodeBoolForKey: 返回 NO,decodeIntForKey: 返回 0,decodeObjectForKey: 返回 nil。

      这些是您得到的错误值。首先,我注意到您没有进行任何错误检查。尝试添加一些检查以查看失败的原因,例如,您可以尝试:

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

      一旦出现错误,我们就可以从那里开始。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-09-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-02-03
        • 2015-06-19
        • 2014-01-16
        相关资源
        最近更新 更多