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

发布于 2024-09-02 07:27:12 字数 2474 浏览 1 评论 0原文

我正在解析一些输入,该输入会生成一个树结构,其中包含分支上的 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 的地方,你会感觉非常笨拙,取出现有的字典,创建它的不可变版本,添加新值,然后从中创建一个不可变的字典来设置就位。又贵又没必要?

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

I'm parsing some input which produces a tree structure containing NSDictionary instances on the branches and NSString instance at the nodes.

After parsing, the whole structure should be immutable. I feel like I'm jumping through hoops to create the structure and then make sure it's immutable when it's returned from my method.

We can probably all relate to the input I'm parsing, since it's a query string from a URL. In a string like this:

a=foo&b=bar&a=zip

We expect a structure like this:

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

I'm keeping it just two-dimensional in this example for brevity, though in the real-world we sometimes see var[key1][key2]=value&var[key1][key3]=value2 type structures. The code hasn't evolved that far just yet.

Currently I do this:

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

If you look at the bit where I've added FIXME it feels awfully clumsy, pulling out the existing dictionary, creating an immutable version of it, adding the new value, then creating an immutable dictionary from that to set back in place. Expensive and unnecessary?

I'm not sure if there are any Cocoa-specific design patterns I can follow here?

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

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

发布评论

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

评论(1

神爱温柔 2024-09-09 07:27:12

昂贵且不必要?

是的。 Apple 的 Cocoa API 通常它们返回一个不可变对象,但实际上返回一个已转换为不可变版本的可变子类。这是标准操作程序,也是公认的 Cocoa 设计原则。您只需相信您的客户不会将其转换回可变版本并从您的底层进行更改。

来自 Cocoa 核心能力:对象可变性

接收可变对象

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

另请参阅:Cocoa 基础指南:Cocoa 对象

Expensive and unnecessary?

Yes. Apple's Cocoa APIs regularly say they return an immutable object, but actually return a mutable subclass that's been cast to the immutable version. This is a standard operating procedure and an accepted Cocoa design principle. You just trust that your clients aren't going to cast it back to a mutable version and change things from underneath you.

From Cocoa Core Competencies: Object Mutability:

Receiving Mutable Objects

When you call a method and receive an object in return, the object could be mutable even if the method’s return type characterizes it as immutable. There is nothing to prevent a class from declaring a method to return an immutable object but returning a mutable object in its implementation. Although you could use introspection to determine whether a received object is actually mutable or immutable, you shouldn’t. Always use the return type of an object to judge its mutability.

See also: Cocoa Fundamentals Guide: Cocoa Objects.

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