从使用 NSKeyedArchiver 存储的 NSMutableArray 内的 NSDictionary 读取字符串时出现问题

发布于 2024-08-12 14:58:06 字数 3989 浏览 5 评论 0原文

我使用一系列 NSDictionaries 保存一些数据,存储在 NSMutableArray 中并使用 NSKeyedArchiver 存档。

我基本上试图保存类“Brick”的几个实例的状态,所以我实现了像这样的 getBlueprint 方法(精简版)

-(id)getBlueprint
{

    // NOTE: brickColor is a string

 NSDictionary *blueprint = [NSDictionary dictionaryWithObjectsAndKeys: 
       brickColor, @"color",
              [NSNumber numberWithInt:rotation], @"rotation",
       nil];
 return blueprint;

}

所以我有另一种方法,可以在提供蓝图时创建一个新的 Brick 实例。

-(id)initWithBlueprint:(NSDictionary *)blueprint spriteSheet:(NSString *)ssheet
    {
     if((self == [super init])){

      brickColor = [blueprint objectForKey:@"color"];
      [self setColorOffset:brickColor];

      while(rotation != [[blueprint objectForKey:@"rotation"] intValue]){
       [self setRotation:90];
      }
     }

     return self;

    }

当我向它传递一个“新”蓝图时,它会起作用,但当我从保存的文件中读取蓝图时,它就不起作用了......有点。例如,旋转可以工作,但改变颜色则不行。 读取 brickColor 的值

NSLog(@"brick color %@", [blueprint objectForKey:@"color"]);

因此,虽然我可以使用“我知道颜色是紫色”之类的方法来

 if(brickColor == @"purple"){
  colorOffset = CGPointMake(72,36);
  NSLog(@"Changed offset for -- %@ -- to %@", color, NSStringFromCGPoint(colorOffset));
 }

,但条件不会返回 true。我认为可能是 NSKeyedUnarchiver 以某种方式将字符串更改为其他内容,但以下测试返回 true。

if([color isKindOfClass:[NSString class]]){
  NSLog(@"%@ IS A STRING", color);
 }else{
  NSLog(@"!!!!! COLOR IS A NOT STRING !!!!!");
 }

正如我所说,如果我尝试使用新创建的 NSDictionary 作为蓝图,只有当蓝图被存档然后读回时,这不是问题。

所以,像往常一样,我想知道是否有人知道为什么这可能正在发生。

如果相关的话,以下是数据的存储和接收方式。

// Saving    
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

    -(void)buildLevelData{

     levelData = [[NSMutableArray alloc] initWithCapacity:100]; 
     for(brickSprite *brick in spriteHolder.children){

      [levelData addObject:[brick getBlueprint]];

     }

    }



    -(void)saveLevel
    {
     [self buildLevelData];

     NSData *rawDat = [NSKeyedArchiver archivedDataWithRootObject:levelData];

     if([self writeApplicationData:rawDat toFile:saveFileName]){
      NSLog(@"Data Saved");
     }else{
      NSLog(@"ERROR SAVING LEVEL DATA!");
     }
     [[Director sharedDirector] replaceScene:[MainMenu scene]];
    }


    - (BOOL)writeApplicationData:(NSData *)data toFile:(NSString *)fileName {
        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        NSString *documentsDirectory = [paths objectAtIndex:0];
        if (!documentsDirectory) {
            NSLog(@"Documents directory not found!");
            return NO;
        }
        NSString *appFile = [saveDir stringByAppendingPathComponent:fileName];
        return ([data writeToFile:appFile atomically:YES]);
    }

// Loading
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
- (void) loadRandomMapFrom:(NSString *)dir
{

 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
 NSString *docsDir = [paths objectAtIndex:0];

 if(!docsDir){
  NSLog(@"Cound Not Find Documents Directory When trying To Load Random Map");
  return;
 }

 dir = [docsDir stringByAppendingPathComponent:[NSString stringWithFormat:@"/%@", dir]];

 // we'll also set the file name here. 
 NSArray *existingFiles = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:dir error:nil];

 // get last file for this test
 NSString *filePath = [dir stringByAppendingPathComponent:[existingFiles objectAtIndex:([existingFiles count] - 1)]];

 NSMutableArray *levelData = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];

 [self buildMapWithData:levelData];
}



-(void)buildMapWithData:(NSMutableArray *)lData
{

 for(NSDictionary *blueprint in lData){

  brickSprite *brick = [[brickSprite alloc] initWithBlueprint:blueprint spriteSheet:@"blocks.png"];
  [spriteHolder addChild:brick];
 }

}

抱歉问题有点混乱。有很多事情让我很难完全理解自己,所以很难将其分解到最低限度。

I'm saving some data using a series of NSDictionaries, stored in an NSMutableArray and archived using NSKeyedArchiver.

I'm basically trying to save the states of several instances the class 'Brick', so I've implemented a getBlueprint method like this (slimmed down version)

-(id)getBlueprint
{

    // NOTE: brickColor is a string

 NSDictionary *blueprint = [NSDictionary dictionaryWithObjectsAndKeys: 
       brickColor, @"color",
              [NSNumber numberWithInt:rotation], @"rotation",
       nil];
 return blueprint;

}

And so I have another method that creates a new Brick instance when provided with a blueprint.

-(id)initWithBlueprint:(NSDictionary *)blueprint spriteSheet:(NSString *)ssheet
    {
     if((self == [super init])){

      brickColor = [blueprint objectForKey:@"color"];
      [self setColorOffset:brickColor];

      while(rotation != [[blueprint objectForKey:@"rotation"] intValue]){
       [self setRotation:90];
      }
     }

     return self;

    }

Which works when I pass it a 'fresh' blueprint, but not when I read a blueprint from a saved file... sort of. For example, the rotation will work, but changing the color wont. So while I can read the value of brickColor using

NSLog(@"brick color %@", [blueprint objectForKey:@"color"]);

if I try something like

 if(brickColor == @"purple"){
  colorOffset = CGPointMake(72,36);
  NSLog(@"Changed offset for -- %@ -- to %@", color, NSStringFromCGPoint(colorOffset));
 }

And I know that color is purple, the condition doesn't return true. I thought it might be that somehow NSKeyedUnarchiver changed a string into something else, but the following test returns true.

if([color isKindOfClass:[NSString class]]){
  NSLog(@"%@ IS A STRING", color);
 }else{
  NSLog(@"!!!!! COLOR IS A NOT STRING !!!!!");
 }

As I said, this isn't a problem if I try to use a freshly created NSDictionary as a blueprint, only when a blueprint is archived and then read back in.

So, as usual, I'm wondering if anyone has any ideas why this might be happening.

incase it's relevant, here's how the data is being stored and recieved.

// Saving    
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

    -(void)buildLevelData{

     levelData = [[NSMutableArray alloc] initWithCapacity:100]; 
     for(brickSprite *brick in spriteHolder.children){

      [levelData addObject:[brick getBlueprint]];

     }

    }



    -(void)saveLevel
    {
     [self buildLevelData];

     NSData *rawDat = [NSKeyedArchiver archivedDataWithRootObject:levelData];

     if([self writeApplicationData:rawDat toFile:saveFileName]){
      NSLog(@"Data Saved");
     }else{
      NSLog(@"ERROR SAVING LEVEL DATA!");
     }
     [[Director sharedDirector] replaceScene:[MainMenu scene]];
    }


    - (BOOL)writeApplicationData:(NSData *)data toFile:(NSString *)fileName {
        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        NSString *documentsDirectory = [paths objectAtIndex:0];
        if (!documentsDirectory) {
            NSLog(@"Documents directory not found!");
            return NO;
        }
        NSString *appFile = [saveDir stringByAppendingPathComponent:fileName];
        return ([data writeToFile:appFile atomically:YES]);
    }

// Loading
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
- (void) loadRandomMapFrom:(NSString *)dir
{

 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
 NSString *docsDir = [paths objectAtIndex:0];

 if(!docsDir){
  NSLog(@"Cound Not Find Documents Directory When trying To Load Random Map");
  return;
 }

 dir = [docsDir stringByAppendingPathComponent:[NSString stringWithFormat:@"/%@", dir]];

 // we'll also set the file name here. 
 NSArray *existingFiles = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:dir error:nil];

 // get last file for this test
 NSString *filePath = [dir stringByAppendingPathComponent:[existingFiles objectAtIndex:([existingFiles count] - 1)]];

 NSMutableArray *levelData = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];

 [self buildMapWithData:levelData];
}



-(void)buildMapWithData:(NSMutableArray *)lData
{

 for(NSDictionary *blueprint in lData){

  brickSprite *brick = [[brickSprite alloc] initWithBlueprint:blueprint spriteSheet:@"blocks.png"];
  [spriteHolder addChild:brick];
 }

}

Sorry about the mess of a question. There's a lot going on that I'm struggling to fully understand myself so it's hard to break it down to the bare minimum.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

皇甫轩 2024-08-19 14:58:06

您应该始终将字符串与 [firstString isEqualToString:secondString] 进行比较,因为 firstString == secondaryString 仅检查指针是否相等,例如,如果两个字符串存储在同一位置(其中在比较动态创建的对象和字符串常量时它们永远不会是)。

You should always compare strings with [firstString isEqualToString:secondString], because firstString == secondString only checks for pointer equality, e.g. if both strings are stored at the same location (which they'll never be when comparing dynamically created objects and string constants).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文