我正在分析一些输入,它生成一个树结构,其中包含分支上的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的地方,会觉得非常笨拙,拉出现有的字典,创建一个不可变的版本,添加新的值,然后从中创建一个不可变的字典来重新设置。昂贵和不必要?
我不确定这里是否有我可以遵循的可可特定的设计模式?