代码之家  ›  专栏  ›  技术社区  ›  d11wtq Vadim Baryshev

创建nsdictionary嵌套树结构的方法?

  •  1
  • d11wtq Vadim Baryshev  · 技术社区  · 14 年前

    我正在分析一些输入,它生成一个树结构,其中包含分支上的nsdictionary实例和节点上的nsstring实例。

    解析之后,整个结构应该是不可变的。我觉得我是在跳铁环来创建结构,然后确保当它从我的方法返回时是不变的。

    我们可能都与要解析的输入相关,因为它是来自URL的查询字符串。在这样的字符串中:

    a=foo&b=bar&a=zip
    

    我们期望这样的结构:

    NSDictionary {
      "a" => NSDictionary {
        0 => "foo",
        1 => "zip"
      },
      "b" => "bar"
    }
    

    在这个例子中,为了简洁起见,我将它保持为二维的,尽管在现实世界中我们有时会看到 var[key1][key2]=value&var[key1][key3]=value2 类型结构。代码还没有进化到那么远。

    目前我这样做:

    - (NSDictionary *)parseQuery:(NSString *)queryString {
      NSMutableDictionary *params = [NSMutableDictionary dictionary];
      NSArray *pairs = [queryString componentsSeparatedByString:@"&"];
    
      for (NSString *pair in pairs) {
        NSRange eqRange = [pair rangeOfString:@"="];
    
        NSString *key;
        id value;
    
        // If the parameter is a key without a specified value
        if (eqRange.location == NSNotFound) {
          key = [pair stringByReplacingPercentEscapesUsingEncoding:NSASCIIStringEncoding];
          value = @"";
        } else {
          // Else determine both key and value
          key = [[pair substringToIndex:eqRange.location] stringByReplacingPercentEscapesUsingEncoding:NSASCIIStringEncoding];
          if ([pair length] > eqRange.location + 1) {
            value = [[pair substringFromIndex:eqRange.location + 1] stringByReplacingPercentEscapesUsingEncoding:NSASCIIStringEncoding];
          } else {
            value = @"";
          }
        }
    
        // Parameter already exists, it must be a dictionary
        if (nil != [params objectForKey:key]) {
          id existingValue = [params objectForKey:key];
          if (![existingValue isKindOfClass:[NSDictionary class]]) {
            value = [NSDictionary dictionaryWithObjectsAndKeys:existingValue, [NSNumber numberWithInt:0], value, [NSNumber numberWithInt:1], nil];
          } else {
            // FIXME: There must be a more elegant way to build a nested dictionary where the end result is immutable?
            NSMutableDictionary *newValue = [NSMutableDictionary dictionaryWithDictionary:existingValue];
            [newValue setObject:value forKey:[NSNumber numberWithInt:[newValue count]]];
            value = [NSDictionary dictionaryWithDictionary:newValue];
          }
    
        }
    
        [params setObject:value forKey:key];
      }
    
      return [NSDictionary dictionaryWithDictionary:params];
    }
    

    如果你看一下我添加fixme的地方,会觉得非常笨拙,拉出现有的字典,创建一个不可变的版本,添加新的值,然后从中创建一个不可变的字典来重新设置。昂贵和不必要?

    我不确定这里是否有我可以遵循的可可特定的设计模式?

    1 回复  |  直到 14 年前
        1
  •  2
  •   mbauman    14 年前

    昂贵和不必要?

    对。苹果的可可API 它们返回一个不可变的对象,但实际上返回一个已转换为不可变版本的可变子类。这是一个标准的操作程序和公认的可可设计原则。你只是相信你的客户不会把它转换回一个可变的版本,从你的下面改变事情。

    Cocoa Core Competencies: Object Mutability :

    接收可变对象

    当调用方法并接收返回的对象时,对象可能是可变的,即使方法返回类型将其表示为不可变的。没有什么可以阻止类声明方法以返回不可变对象,但在其实现中返回可变对象。虽然您可以使用内省来确定接收到的对象实际上是可变的还是不可变的,但您不应该这样做。始终使用对象的返回类型来判断其可变性。

    参见: Cocoa Fundamentals Guide: Cocoa Objects .