如何从分层的 .plist 中获取值?
How do I get values from a tiered .plist?
I've already looked at Parse Plist (NSString) into NSDictionary and deemed it to be not a duplicate, as that question and its answer do not address my concerns.
我在文件系统中有一个 .plist
文件,结构如下:
此 .plist
文件的源代码如下所示:
{
"My App" = {
"Side Panel" = {
Items = {
Price = "#123ABC";
};
};
};
}
我知道如何像这样在 Root
中获取项目:
[[NSBundle mainBundle] pathForResource:@"filename" ofType:@"plist"];
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path];
NSString value = [dict objectForKey:@"key"]);
但是如果结构像我的一样,有分层字典呢? 如何获取 Price
的值?
我想用一种方法完成这一切,理想情况下是这样的:
通话中
NSString *hexString = [self getColorForKey:@"My App.Side Panel.Items.Price"];
定义
- (NSString *) getColorForKey: (NSString *)key
{
NSArray *path = [key componentsSeparatedByString:@"."];
NSDictionary *colors = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Colors" ofType:@"plist"]];
NSString *color = @"#FFFFFF"; // white is our backup
// What do I put here to get the color?
return color;
}
这是对我有用的解决方案:
+ (NSString*) getHexColorForKey:(NSString*)key
{
NSArray *path = [key componentsSeparatedByString:@"."];
NSDictionary *colors = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Colors" ofType:@"plist"]];
NSString *color = @"#FFFFFF";
for (NSString *location in path) {
NSObject *subdict = colors[location];
if ([subdict isKindOfClass:[NSString class]])
{
color = (NSString*)subdict;
break;
}
else if ([subdict isKindOfClass:[NSDictionary class]])
{
colors = (NSDictionary*)subdict; // if it's a dictinoary, our color may be inside it
}
else
{
[SilverLog level:SilverLogLevelError message:@"Unexpected type of dictinoary entry: %@", [subdict class]];
return color;
}
}
return color;
}
其中 key
是匹配 /^[^.]+(\.[^.]+)*$/
的 NSString
,这意味着它看起来像我的目标 @"My App.Side Panel.Items.Price"
.
是的,我明白你想要完成什么;谢谢你的澄清。不过,我要补充一点,我所写的资源和建议确实提供了解决您问题的必要信息。
就是说,下面是你的字典:
NSURL *plistURL = [[NSBundle mainBundle] URLForResource:@"Info" withExtension:@"plist"];
NSData *plistData = [NSData dataWithContentsOfURL:plistURL];
NSDictionary *tieredPlistData = [NSPropertyListSerialization propertyListWithData:plistData
options:kCFPropertyListImmutable
format:NULL
error:nil];
那么,如果我们对Items
中包含的信息感兴趣
NSDictionary *allItemsDictionary = tieredPlistData[@"My App"][@"Side Panel"][@"Items"];
假设 Items
将包含多个对象,您可以使用
NSArray *keys = [allItems allKeys];
for(NSString *key in keys){
NSString *colorValue = allItemsDictionary[key];
// do something with said color value and key
}
或者,如果您需要一个值,则只需引用该键
NSString *colorForPriceText = allItemsDictionary[@"Price"];
但有几点提示:
- 通常认为将经常访问的值保存在代码中而不是在运行时加载的 plist/file 是更好的主意。
- 就是说,您不会将调用从
NSBundle
加载到与查询特定值相同的方法中。在您的示例中,每次需要一种颜色时,您最终都会重新访问 NSBundle
并堆积不需要的内存分配。一种方法是将 plist 加载到 iVar NSDictionary
中,然后 NSDictionary
将由另一种方法单独使用。
I've already looked at Parse Plist (NSString) into NSDictionary and deemed it to be not a duplicate, as that question and its answer do not address my concerns.
我在文件系统中有一个 .plist
文件,结构如下:
此 .plist
文件的源代码如下所示:
{
"My App" = {
"Side Panel" = {
Items = {
Price = "#123ABC";
};
};
};
}
我知道如何像这样在 Root
中获取项目:
[[NSBundle mainBundle] pathForResource:@"filename" ofType:@"plist"];
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path];
NSString value = [dict objectForKey:@"key"]);
但是如果结构像我的一样,有分层字典呢? 如何获取 Price
的值?
我想用一种方法完成这一切,理想情况下是这样的:
通话中
NSString *hexString = [self getColorForKey:@"My App.Side Panel.Items.Price"];
定义
- (NSString *) getColorForKey: (NSString *)key
{
NSArray *path = [key componentsSeparatedByString:@"."];
NSDictionary *colors = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Colors" ofType:@"plist"]];
NSString *color = @"#FFFFFF"; // white is our backup
// What do I put here to get the color?
return color;
}
这是对我有用的解决方案:
+ (NSString*) getHexColorForKey:(NSString*)key
{
NSArray *path = [key componentsSeparatedByString:@"."];
NSDictionary *colors = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Colors" ofType:@"plist"]];
NSString *color = @"#FFFFFF";
for (NSString *location in path) {
NSObject *subdict = colors[location];
if ([subdict isKindOfClass:[NSString class]])
{
color = (NSString*)subdict;
break;
}
else if ([subdict isKindOfClass:[NSDictionary class]])
{
colors = (NSDictionary*)subdict; // if it's a dictinoary, our color may be inside it
}
else
{
[SilverLog level:SilverLogLevelError message:@"Unexpected type of dictinoary entry: %@", [subdict class]];
return color;
}
}
return color;
}
其中 key
是匹配 /^[^.]+(\.[^.]+)*$/
的 NSString
,这意味着它看起来像我的目标 @"My App.Side Panel.Items.Price"
.
是的,我明白你想要完成什么;谢谢你的澄清。不过,我要补充一点,我所写的资源和建议确实提供了解决您问题的必要信息。
就是说,下面是你的字典:
NSURL *plistURL = [[NSBundle mainBundle] URLForResource:@"Info" withExtension:@"plist"];
NSData *plistData = [NSData dataWithContentsOfURL:plistURL];
NSDictionary *tieredPlistData = [NSPropertyListSerialization propertyListWithData:plistData
options:kCFPropertyListImmutable
format:NULL
error:nil];
那么,如果我们对Items
NSDictionary *allItemsDictionary = tieredPlistData[@"My App"][@"Side Panel"][@"Items"];
假设 Items
将包含多个对象,您可以使用
NSArray *keys = [allItems allKeys];
for(NSString *key in keys){
NSString *colorValue = allItemsDictionary[key];
// do something with said color value and key
}
或者,如果您需要一个值,则只需引用该键
NSString *colorForPriceText = allItemsDictionary[@"Price"];
但有几点提示:
- 通常认为将经常访问的值保存在代码中而不是在运行时加载的 plist/file 是更好的主意。
- 就是说,您不会将调用从
NSBundle
加载到与查询特定值相同的方法中。在您的示例中,每次需要一种颜色时,您最终都会重新访问NSBundle
并堆积不需要的内存分配。一种方法是将 plist 加载到 iVarNSDictionary
中,然后NSDictionary
将由另一种方法单独使用。