patternMinor
Fetch plist file
Viewed 0 times
filefetchplist
Problem
I have a plist file with many nested dictionaries inside of it, and I wanna fetch them all to my code. Isn't there any more efficient way to do that than nested for-loops?
```
NSArray * keys = [plistDictionary allKeys];
for (NSString * key in keys) {
// Level 1
NSLog(@"%@", key );
BOOL isDictionary = [[plistDictionary objectForKey:key] isKindOfClass:[NSDictionary class]];
if (isDictionary) {
NSArray * keys2 = [[plistDictionary objectForKey:key] allKeys];
for (NSString * key2 in keys2) {
// Level 2
NSLog(@"%@ : %@", key, key2 );
BOOL isDictionary = [[[plistDictionary objectForKey:key] objectForKey:key2] isKindOfClass:[NSDictionary class]];
if (isDictionary) {
// Level 3
NSArray *keys3 = [[[plistDictionary objectForKey:key] objectForKey:key2] allKeys];
for (NSString *key3 in keys3) {
NSLog(@"%@ : %@ : %@", key, key2, key3 );
BOOL isDictionary = [[[[plistDictionary objectForKey:key] objectForKey:key2] objectForKey:key3] isKindOfClass:[NSDictionary class]];
if (isDictionary) {
// Level 4
NSArray *keys4 = [[[[plistDictionary objectForKey:key] objectForKey:key2] objectForKey:key3] allKeys];
for (NSString * key4 in keys4) {
NSLog(@ "%@ : %@ : %@ : %@",key, key2, key3, key4 );
BOOL isDictionary = [[[[[plistDictionary objectForKey:key] objectForKey:key2] objectForKey:key3] objectForKey:key4] isKindOfClass:[NSDictionary class]];
if (isDictionary) {
// Level 5
NSArray * keys5 = [[[[[plistDictionary objectForKey:key] objectForKey:key2] objectForKey:key3] objectForKey:key4] allKeys];
for (NSString * key5 in keys5) {
```
NSArray * keys = [plistDictionary allKeys];
for (NSString * key in keys) {
// Level 1
NSLog(@"%@", key );
BOOL isDictionary = [[plistDictionary objectForKey:key] isKindOfClass:[NSDictionary class]];
if (isDictionary) {
NSArray * keys2 = [[plistDictionary objectForKey:key] allKeys];
for (NSString * key2 in keys2) {
// Level 2
NSLog(@"%@ : %@", key, key2 );
BOOL isDictionary = [[[plistDictionary objectForKey:key] objectForKey:key2] isKindOfClass:[NSDictionary class]];
if (isDictionary) {
// Level 3
NSArray *keys3 = [[[plistDictionary objectForKey:key] objectForKey:key2] allKeys];
for (NSString *key3 in keys3) {
NSLog(@"%@ : %@ : %@", key, key2, key3 );
BOOL isDictionary = [[[[plistDictionary objectForKey:key] objectForKey:key2] objectForKey:key3] isKindOfClass:[NSDictionary class]];
if (isDictionary) {
// Level 4
NSArray *keys4 = [[[[plistDictionary objectForKey:key] objectForKey:key2] objectForKey:key3] allKeys];
for (NSString * key4 in keys4) {
NSLog(@ "%@ : %@ : %@ : %@",key, key2, key3, key4 );
BOOL isDictionary = [[[[[plistDictionary objectForKey:key] objectForKey:key2] objectForKey:key3] objectForKey:key4] isKindOfClass:[NSDictionary class]];
if (isDictionary) {
// Level 5
NSArray * keys5 = [[[[[plistDictionary objectForKey:key] objectForKey:key2] objectForKey:key3] objectForKey:key4] allKeys];
for (NSString * key5 in keys5) {
Solution
The first thing you can do is to store the intermediate objects in variables,
in order to get rid of the repeated and deeply nested
like
Then it would look like this:
Note also the use of the dictionary subscripting syntax instead of
This can be simplified further by using the
method of
key and the corresponding value:
This is still a lot of repeated code, and can be further simplified using
recursion:
But what if the plist has not only dictionaries but also arrays as "nested structures"
(array in dictionary, dictionary in array, array in array, ...)?
That is not too complicated in the recursive version, we only have to test for
dictionary or array type. The function now takes an generic
and then enumerates the dict or array and calls itself recursively. We can also
print the "terminal nodes" or "values", i.e. everything that is not a collection
(strings, numbers, ...):
That works, but it doe
in order to get rid of the repeated and deeply nested
objectForKey: chainslike
NSArray *keys4 = [[[[plistDictionary objectForKey:key] objectForKey:key2] objectForKey:key3] allKeys];Then it would look like this:
NSArray * keys = [plistDictionary allKeys];
for (NSString * key in keys) {
// Level 1
NSLog(@"%@", key );
NSDictionary *obj1 = plistDictionary[key];
if ([obj1 isKindOfClass:[NSDictionary class]]) {
NSArray * keys2 = [obj1 allKeys];
for (NSString * key2 in keys2) {
// Level 2
NSLog(@"%@ : %@", key, key2 );
NSDictionary *obj2 = obj1[key2];
if ([obj2 isKindOfClass:[NSDictionary class]]) {
// Level 3
NSArray *keys3 = [obj2 allKeys];
for (NSString *key3 in keys3) {
NSLog(@"%@ : %@ : %@", key, key2, key3 );
NSDictionary *obj3 = obj2[key3];
// ...
}
}
}
}
}Note also the use of the dictionary subscripting syntax instead of
objectForKey:.This can be simplified further by using the
enumerateKeysAndObjectsUsingBlock:method of
NSDictionary. This method calls the given block once for eachkey and the corresponding value:
[plistDictionary enumerateKeysAndObjectsUsingBlock:^(NSString *key1, NSDictionary *obj1, BOOL *stop) {
NSLog(@"%@", key1);
if ([obj1 isKindOfClass:[NSDictionary class]]) {
[obj1 enumerateKeysAndObjectsUsingBlock:^(NSString *key2, NSDictionary *obj2, BOOL *stop) {
NSLog(@"%@ : %@", key1, key2);
if ([obj2 isKindOfClass:[NSDictionary class]]) {
[obj2 enumerateKeysAndObjectsUsingBlock:^(NSString *key3, NSDictionary *obj3, BOOL *stop) {
NSLog(@"%@ : %@ : %@", key1, key2, key3);
if ([obj3 isKindOfClass:[NSDictionary class]]) {
[obj3 enumerateKeysAndObjectsUsingBlock:^(NSString *key4, NSDictionary *obj4, BOOL *stop) {
NSLog(@ "%@ : %@ : %@ : %@", key1, key2, key3, key4);
if ([obj4 isKindOfClass:[NSDictionary class]]) {
[obj4 enumerateKeysAndObjectsUsingBlock:^(NSString *key5, NSDictionary *obj5, BOOL *stop) {
NSLog(@"%@ : %@ : %@ : %@ : %@", key1, key2, key3, key4, key5);
}];
}
}];
}
}];
}
}];
}
}];This is still a lot of repeated code, and can be further simplified using
recursion:
-(void)printPlist:(NSDictionary *)plistDictionary previousKeys:(NSArray *)previousKeys {
[plistDictionary enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSDictionary *obj, BOOL *stop) {
NSArray *newKeys = [previousKeys arrayByAddingObject:key];
NSLog(@"%@", [newKeys componentsJoinedByString:@" : "]);
if ([obj isKindOfClass:[NSDictionary class]]) {
[self printPlist:obj previousKeys:newKeys];
}
}];
}
-(void)printPlist:(NSDictionary *)plistDictionary {
[self printPlist:plistDictionary previousKeys:@[]];
}But what if the plist has not only dictionaries but also arrays as "nested structures"
(array in dictionary, dictionary in array, array in array, ...)?
That is not too complicated in the recursive version, we only have to test for
dictionary or array type. The function now takes an generic
id parameterand then enumerates the dict or array and calls itself recursively. We can also
print the "terminal nodes" or "values", i.e. everything that is not a collection
(strings, numbers, ...):
-(void)printPlist:(id)plistObject previousKeys:(NSArray *)previousKeys {
if ([plistObject isKindOfClass:[NSDictionary class]]) {
// Enumerate dictionary:
[(NSDictionary *)plistObject enumerateKeysAndObjectsUsingBlock:^(NSString *key, id obj, BOOL *stop) {
NSArray *newKeys = [previousKeys arrayByAddingObject:key];
NSLog(@"%@", [newKeys componentsJoinedByString:@" : "]);
[self printPlist:obj previousKeys:newKeys];
}];
} else if ([plistObject isKindOfClass:[NSArray class]]) {
// Enumerate array:
[(NSArray *)plistObject enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSArray *newKeys = [previousKeys arrayByAddingObject:@(idx)];
NSLog(@"%@", [newKeys componentsJoinedByString:@" : "]);
[self printPlist:obj previousKeys:newKeys];
}];
} else {
// Not a collection, print keys and value:
NSLog(@"%@ = %@", [previousKeys componentsJoinedByString:@" : "], plistObject);
}
}
-(void)printPlist:(id)plistObject {
[self printPlist:plistObject previousKeys:@[]];
}That works, but it doe
Code Snippets
NSArray *keys4 = [[[[plistDictionary objectForKey:key] objectForKey:key2] objectForKey:key3] allKeys];NSArray * keys = [plistDictionary allKeys];
for (NSString * key in keys) {
// Level 1
NSLog(@"%@", key );
NSDictionary *obj1 = plistDictionary[key];
if ([obj1 isKindOfClass:[NSDictionary class]]) {
NSArray * keys2 = [obj1 allKeys];
for (NSString * key2 in keys2) {
// Level 2
NSLog(@"%@ : %@", key, key2 );
NSDictionary *obj2 = obj1[key2];
if ([obj2 isKindOfClass:[NSDictionary class]]) {
// Level 3
NSArray *keys3 = [obj2 allKeys];
for (NSString *key3 in keys3) {
NSLog(@"%@ : %@ : %@", key, key2, key3 );
NSDictionary *obj3 = obj2[key3];
// ...
}
}
}
}
}[plistDictionary enumerateKeysAndObjectsUsingBlock:^(NSString *key1, NSDictionary *obj1, BOOL *stop) {
NSLog(@"%@", key1);
if ([obj1 isKindOfClass:[NSDictionary class]]) {
[obj1 enumerateKeysAndObjectsUsingBlock:^(NSString *key2, NSDictionary *obj2, BOOL *stop) {
NSLog(@"%@ : %@", key1, key2);
if ([obj2 isKindOfClass:[NSDictionary class]]) {
[obj2 enumerateKeysAndObjectsUsingBlock:^(NSString *key3, NSDictionary *obj3, BOOL *stop) {
NSLog(@"%@ : %@ : %@", key1, key2, key3);
if ([obj3 isKindOfClass:[NSDictionary class]]) {
[obj3 enumerateKeysAndObjectsUsingBlock:^(NSString *key4, NSDictionary *obj4, BOOL *stop) {
NSLog(@ "%@ : %@ : %@ : %@", key1, key2, key3, key4);
if ([obj4 isKindOfClass:[NSDictionary class]]) {
[obj4 enumerateKeysAndObjectsUsingBlock:^(NSString *key5, NSDictionary *obj5, BOOL *stop) {
NSLog(@"%@ : %@ : %@ : %@ : %@", key1, key2, key3, key4, key5);
}];
}
}];
}
}];
}
}];
}
}];-(void)printPlist:(NSDictionary *)plistDictionary previousKeys:(NSArray *)previousKeys {
[plistDictionary enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSDictionary *obj, BOOL *stop) {
NSArray *newKeys = [previousKeys arrayByAddingObject:key];
NSLog(@"%@", [newKeys componentsJoinedByString:@" : "]);
if ([obj isKindOfClass:[NSDictionary class]]) {
[self printPlist:obj previousKeys:newKeys];
}
}];
}
-(void)printPlist:(NSDictionary *)plistDictionary {
[self printPlist:plistDictionary previousKeys:@[]];
}-(void)printPlist:(id)plistObject previousKeys:(NSArray *)previousKeys {
if ([plistObject isKindOfClass:[NSDictionary class]]) {
// Enumerate dictionary:
[(NSDictionary *)plistObject enumerateKeysAndObjectsUsingBlock:^(NSString *key, id obj, BOOL *stop) {
NSArray *newKeys = [previousKeys arrayByAddingObject:key];
NSLog(@"%@", [newKeys componentsJoinedByString:@" : "]);
[self printPlist:obj previousKeys:newKeys];
}];
} else if ([plistObject isKindOfClass:[NSArray class]]) {
// Enumerate array:
[(NSArray *)plistObject enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSArray *newKeys = [previousKeys arrayByAddingObject:@(idx)];
NSLog(@"%@", [newKeys componentsJoinedByString:@" : "]);
[self printPlist:obj previousKeys:newKeys];
}];
} else {
// Not a collection, print keys and value:
NSLog(@"%@ = %@", [previousKeys componentsJoinedByString:@" : "], plistObject);
}
}
-(void)printPlist:(id)plistObject {
[self printPlist:plistObject previousKeys:@[]];
}Context
StackExchange Code Review Q#68340, answer score: 5
Revisions (0)
No revisions yet.