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

时间:2010-05-22 03:35:13

标签: objective-c dictionary tree

我正在解析一些输入,这些输入产生一个树结构,其中包含分支上的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的位置,感觉非常笨拙,拉出现有的字典,创建它的不可变版本,添加新值,然后创建一个不可变的字典,以便设置回原位。贵又不必要?

我不确定我是否可以遵循特定于Cocoa的设计模式?

1 个答案:

答案 0 :(得分:2)

  

贵而且不必要?

是。 Apple的Cocoa API定期它们返回一个不可变对象,但实际上返回一个可变子类,它已被强制转换为不可变版本。这是一个标准的操作程序和公认的Cocoa设计原则。您只是相信您的客户不会将其转换回可变版本并从您下方更改内容。

来自Cocoa Core Competencies: Object Mutability

  

接收可变对象

     

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

另请参阅:Cocoa Fundamentals Guide: Cocoa Objects