__NSDictionaryM was mutated while being enumerated - objective-c

I'm trying to set all keys from my NSMutableDictionary as 0, but I'm getting the following error:
__NSDictionaryM was mutated while being enumerated
There's my code:
-(void)marcarTodosRoteiros {
_numeroRoteirosSelecionados = (int)[self.roteirosSelecionados count];
for(id key in self.roteirosSelecionados) {
[self.roteirosSelecionados setObject:#"1" forKey:key];
}
[self.tbFiltros reloadData];
}

This is the enumeration:
for(id key in self.roteirosSelecionados)
and this is the mutation:
[self.roteirosSelecionados setObject:#"1" forKey:key];
You cannot do that. What you should do in this case is get all the keys into a separate array and then set #"1" for each key:
-(void)marcarTodosRoteiros {
NSArray *keys = [self.roteirosSelecionados allKeys];
for (NSString *key in keys)
[self.roteirosSelecionados setObject:#"1" forKey:key];
[self.tbFiltros reloadData];
}

Related

Trying to sort sections in descending order

self.sections = [[NSMutableDictionary alloc] init];
BOOL found;
for (NSDictionary *wine in sortedWines)
{
NSNumber *rate = [wine valueForKey:#"Rate"];
NSString *rateStr = [NSString stringWithFormat:#"%.f", [rate floatValue]];
found = NO;
for (NSString *str in [self.sections allKeys])
{
if ([str isEqualToString:rateStr])
{
found = YES;
}
}
if (!found)
{[self.sections setValue:[[NSMutableArray alloc] init] forKey:rateStr];}
}
for (NSDictionary *wine in sortedWines)
{[[self.sections objectForKey:[NSString stringWithFormat:#"%.f", [[wine valueForKey:#"Rate"] floatValue]] ] addObject:wine];}
// Sort:
for (NSString *key in [self.sections allKeys])
{[[self.sections objectForKey:key] sortUsingDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:#"Rate" ascending:NO]]];}
This code puts my wines in sections, but it won't sort them in descending order! Could it be because the NSNumber is transformed into NSString? I've tried to make a code using the NSNumber value:
self.sections = [[NSMutableDictionary alloc] init];
BOOL found;
for (NSDictionary *wine in sortedWines)
{
NSNumber *rate = [wine valueForKey:#"Rate"];
found = NO;
for (NSNumber *str in [self.sections allKeys])
{
if ([str isEqualToNumber:rate])
{
found = YES;
}
}
if (!found)
{[self.sections setValue:[[NSMutableArray alloc] init] forKey:rate];}
}
// Loop again to sort wines into their keys
for (NSDictionary *wine in sortedWines)
{[[self.sections objectForKey:[wine valueForKey:#"Rate"]] addObject:wine];}
// Sort each section array
for (NSString *key in [self.sections allKeys])
{[[self.sections objectForKey:key] sortUsingDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:#"Rate" ascending:NO]]];}
But it gives a warning for
if (!found)
{[self.sections setValue:[[NSMutableArray alloc] init] forKey:rate];}
that says "Incompatible pointer types sending NSNumber ___strong to parameter of type NSString"
If I run the app it crashes with error -[__NSCFNumber localizedCaseInsensitiveCompare:]: unrecognized selector sent to instance 0x1e085810
What do I have to change to make it work and sort the sections in descending order? Thanks.
I don't know if the default selector for sortDescriptorWithKey:ascending: is now caseInsensitiveCompare:, I'm pretty sure it used to be just compare:. In any case, you can use sortDescriptorWithKey:ascending:selector:, instead, and pass compare: for the selector. I think that should fix your second error. Still not sure why you're getting that first error.
You would do much better (and we'd understand you better) if you formatted your code for legibility. Eg:
// Loop again to sort wines into their keys
for (NSDictionary *wine in sortedWines) {
NSArray* section = [self.sections objectForKey:[wine valueForKey:#"Rate"]];
[section addObject:wine];
}
// Sort each section array
NSArray* sortDescriptorArray = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:#"Rate" ascending:NO]];
for (NSString *key in [self.sections allKeys]) {
NSArray* section = [self.sections objectForKey:key];
[section sortUsingDescriptors:sortDescriptorArray];
}
Among other things, this makes debugging much simpler since you can stop and dump the section arrays.
Or, if you really liked it better the other way, I can highly recommend that you learn APL or LISP instead.

NSManagedObject to NSDictionary

Trying to serialise NSManagedObject to NSDictionary including related data.
I found some code for that here:
http://vladimir.zardina.org/2010/03/serializing-archivingunarchiving-an-nsmanagedobject-graph/
Unfortunately, there is no support for NSOrderedSet. Tried to implement it myself, but have a crash with message doesn't recognise selector on line if (!relatedObject.traversed) {.
- (NSDictionary*) toDictionary
{
self.traversed = YES;
NSArray* attributes = [[[self entity] attributesByName] allKeys];
NSArray* relationships = [[[self entity] relationshipsByName] allKeys];
NSMutableDictionary* dict = [NSMutableDictionary dictionaryWithCapacity:
[attributes count] + [relationships count] + 1];
[dict setObject:[[self class] description] forKey:#"class"];
for (NSString* attr in attributes) {
NSObject* value = [self valueForKey:attr];
if (value != nil) {
[dict setObject:value forKey:attr];
}
}
for (NSString* relationship in relationships) {
NSObject* value = [self valueForKey:relationship];
if ([value isKindOfClass:[NSSet class]]) {
// To-many relationship
// The core data set holds a collection of managed objects
NSSet* relatedObjects = (NSSet*) value;
// Our set holds a collection of dictionaries
NSMutableSet* dictSet = [NSMutableSet setWithCapacity:[relatedObjects count]];
for (ExtendedManagedObject* relatedObject in relatedObjects) {
if (!relatedObject.traversed) {
[dictSet addObject:[relatedObject toDictionary]];
}
}
[dict setObject:dictSet forKey:relationship];
}
else if ([value isKindOfClass:[NSOrderedSet class]]) {
// To-many relationship
// The core data set holds a collection of managed objects
NSOrderedSet* relatedObjects = (NSOrderedSet *)value;
// Our set holds a collection of dictionaries
NSMutableSet* dictSet = [NSMutableSet setWithCapacity:[relatedObjects count]];
for (ExtendedManagedObject* relatedObject in relatedObjects) {
if (!relatedObject.traversed) {
[dictSet addObject:[relatedObject toDictionary]];
}
}
[dict setObject:dictSet forKey:relationship];
}
else if ([value isKindOfClass:[ExtendedManagedObject class]]) {
// To-one relationship
ExtendedManagedObject* relatedObject = (ExtendedManagedObject*) value;
if (!relatedObject.traversed) {
// Call toDictionary on the referenced object and put the result back into our dictionary.
[dict setObject:[relatedObject toDictionary] forKey:relationship];
}
}
}
return dict;
}
- (void) populateFromDictionary:(NSDictionary*)dict
{
NSManagedObjectContext* context = [self managedObjectContext];
for (NSString* key in dict) {
if ([key isEqualToString:#"class"]) {
continue;
}
NSObject* value = [dict objectForKey:key];
if ([value isKindOfClass:[NSDictionary class]]) {
// This is a to-one relationship
ExtendedManagedObject* relatedObject =
[ExtendedManagedObject createManagedObjectFromDictionary:(NSDictionary*)value
inContext:context];
[self setValue:relatedObject forKey:key];
}
else if ([value isKindOfClass:[NSSet class]]) {
// This is a to-many relationship
NSSet* relatedObjectDictionaries = (NSSet*) value;
// Get a proxy set that represents the relationship, and add related objects to it.
// (Note: this is provided by Core Data)
NSMutableSet* relatedObjects = [self mutableSetValueForKey:key];
for (NSDictionary* relatedObjectDict in relatedObjectDictionaries) {
ExtendedManagedObject* relatedObject =
[ExtendedManagedObject createManagedObjectFromDictionary:relatedObjectDict
inContext:context];
[relatedObjects addObject:relatedObject];
}
}
else if (value != nil) {
// This is an attribute
[self setValue:value forKey:key];
}
}
}
it is fast and easy way
NSMutableArray *array = [NSMutableArray arrayWithCapacity:ManagedObjectItems.count];
[[ManagedObjectItems allObjects] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
Diary_item_food *food = obj;
NSArray *keys = [[[food entity] attributesByName] allKeys];
NSDictionary *dict = [obj dictionaryWithValuesForKeys:keys];
[array addObject:dict];
}];
I found the ready gist on Gihub: https://gist.github.com/nuthatch/5607405
Even easier way, query for the objectID and use NSDictionaryResultType on the fetch request.
Update: Only if you don't need related data.

changing a key name in NSDictionary

I have a method which returns me a nsdictionary with certain keys and values. i need to change the key names from the dictionary to a new key name but the values need to be same for that key,but i am stuck here.need help
This method will only work with a mutable dictionary. It doesn't check what should be done if the new key already exists.
You can get a mutable dictionary of a immutable by calling mutableCopy on it.
- (void)exchangeKey:(NSString *)aKey withKey:(NSString *)aNewKey inMutableDictionary:(NSMutableDictionary *)aDict
{
if (![aKey isEqualToString:aNewKey]) {
id objectToPreserve = [aDict objectForKey:aKey];
[aDict setObject:objectToPreserve forKey:aNewKey];
[aDict removeObjectForKey:aKey];
}
}
You can't change anything in an NSDictionary, since it is read only.
How about loop through the dictionary and create a new NSMutableDictionary with the new key names ?
Could you not add a new key-value pair using the old value, and then remove the old key-value pair?
This would only work on an NSMutableDictionary. NSDictionarys are not designed to be changed once they have been created.
To change specific key to new key, I have written a recursive method for Category Class.
- (NSMutableDictionary*)replaceKeyName:(NSString *)old_key with:(NSString )new_key {
NSMutableDictionary dict = [NSMutableDictionary dictionaryWithDictionary: self];
NSMutableArray *keys = [[dict allKeys] mutableCopy];
for (NSString key in keys) {
if ([key isEqualToString:old_key]) {
id val = [self objectForKey:key];
[dict removeObjectForKey:key];
[dict setValue:val forKey:new_key];
return dict;
} else {
const id object = [dict objectForKey: key];
if ([object isKindOfClass:[NSDictionary class]]) {
[dict setObject:[dict replaceKeyName:old_key with:new_key] forKey:key];
} else if ([object isKindOfClass:[NSArray class]]){
if (object && [(NSArray)object count] > 0) {
NSMutableArray *arr_temp = [[NSMutableArray alloc] init];
for (NSDictionary *temp_dict in object) {
NSDictionary *temp = [temp_dict replaceKeyName:old_key with:new_key];
[arr_temp addObject:temp];
}
[dict setValue:arr_temp forKey:key];
}
}
}
}
return dict;
}

Deep combine NSDictionaries

I need to merge two NSDictionarys into one provided that if there are dictionaries within the dictionaries, they are also merged.
More or less like jQuery's extend function.
NSDictionary+Merge.h
#import <Foundation/Foundation.h>
#interface NSDictionary (Merge)
+ (NSDictionary *) dictionaryByMerging: (NSDictionary *) dict1 with: (NSDictionary *) dict2;
- (NSDictionary *) dictionaryByMergingWith: (NSDictionary *) dict;
#end
NSDictionary+Merge.m
#import "NSDictionary+Merge.h"
#implementation NSDictionary (Merge)
+ (NSDictionary *) dictionaryByMerging: (NSDictionary *) dict1 with: (NSDictionary *) dict2 {
NSMutableDictionary * result = [NSMutableDictionary dictionaryWithDictionary:dict1];
[dict2 enumerateKeysAndObjectsUsingBlock: ^(id key, id obj, BOOL *stop) {
if (![dict1 objectForKey:key]) {
if ([obj isKindOfClass:[NSDictionary class]]) {
NSDictionary * newVal = [[dict1 objectForKey: key] dictionaryByMergingWith: (NSDictionary *) obj];
[result setObject: newVal forKey: key];
} else {
[result setObject: obj forKey: key];
}
}
}];
return (NSDictionary *) [[result mutableCopy] autorelease];
}
- (NSDictionary *) dictionaryByMergingWith: (NSDictionary *) dict {
return [[self class] dictionaryByMerging: self with: dict];
}
#end
I think this is what you're looking for:
First, you need to make a deep mutable copy, so you can create a category on NSDictionary to do this:
#implementation NSDictionary (DeepCopy)
- (id)deepMutableCopy
{
id copy(id obj) {
id temp = [obj mutableCopy];
if ([temp isKindOfClass:[NSArray class]]) {
for (int i = 0 ; i < [temp count]; i++) {
id copied = [copy([temp objectAtIndex:i]) autorelease];
[temp replaceObjectAtIndex:i withObject:copied];
}
} else if ([temp isKindOfClass:[NSDictionary class]]) {
NSEnumerator *enumerator = [temp keyEnumerator];
NSString *nextKey;
while (nextKey = [enumerator nextObject])
[temp setObject:[copy([temp objectForKey:nextKey]) autorelease]
forKey:nextKey];
}
return temp;
}
return (copy(self));
}
#end
Then, you can call deepMutableCopy like this:
NSMutableDictionary *someDictionary = [someDict deepMutableCopy];
[someDictionary addEntriesFromDictionary:otherDictionary];
I added this to the code mentioned above. It may not be fully correct, but it handles the case where 2 dict has an element that 1 dict does not.
+ (NSDictionary *) dictionaryByMerging: (NSDictionary *) dict1 with: (NSDictionary *) dict2 {
NSMutableDictionary * result = [NSMutableDictionary dictionaryWithDictionary:dict1];
NSMutableDictionary * resultTemp = [NSMutableDictionary dictionaryWithDictionary:dict1];
[resultTemp addEntriesFromDictionary:dict2];
[resultTemp enumerateKeysAndObjectsUsingBlock: ^(id key, id obj, BOOL *stop) {
if ([dict1 objectForKey:key]) {
if ([obj isKindOfClass:[NSDictionary class]]) {
NSDictionary * newVal = [[dict1 objectForKey: key] dictionaryByMergingWith: (NSDictionary *) obj];
[result setObject: newVal forKey: key];
} else {
[result setObject: obj forKey: key];
}
}
else if([dict2 objectForKey:key])
{
if ([obj isKindOfClass:[NSDictionary class]]) {
NSDictionary * newVal = [[dict2 objectForKey: key] dictionaryByMergingWith: (NSDictionary *) obj];
[result setObject: newVal forKey: key];
} else {
[result setObject: obj forKey: key];
}
}
}];
return (NSDictionary *) [[result mutableCopy] autorelease];
}
I came here looking for a copy of jQuery's extend but I ended up writing my own implementation. It's a super simple implementation, I did it so I'd understand a way to do it.
+(NSDictionary*) dictionaryByExtending:(NSDictionary*)baseDictionary WithDictionary:(NSDictionary*)extensionDictionary {
NSMutableDictionary * resultDictionary = [NSMutableDictionary dictionaryWithDictionary:baseDictionary];
[extensionDictionary enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
BOOL isDict = [obj isKindOfClass:[NSDictionary class]];
BOOL hasValue = [baseDictionary hasObjectForKey:key] != nil;
id setObj = obj;
if( hasValue && isDict ) {
BOOL hasDict = [[baseDictionary objectForKey:key] isKindOfClass:[NSDictionary class]];
if( hasDict ) {
NSDictionary * extendedChildDictionary = [NSDictionary dictionaryByExtending:[baseDictionary objectForKey:key] WithDictionary:obj];
setObj = extendedChildDictionary;
}
}
[resultDictionary setObject:setObj forKey:key];
}];
return resultDictionary;
}
-(NSDictionary*) dictionaryByExtendingWithDictionary:(NSDictionary*)extensionDictionary {
return [NSDictionary dictionaryByExtending:self WithDictionary:extensionDictionary];
}
Hopefully someone will find this helpful, it worked in my tests with deep-recursion. I'm using it to extend deep JSON files full of text.
Alexsander Akers works for me except the case where dict2 contains a dictionary that's missing from dict1 - it crashes. I changed the logic to this:
+ (NSDictionary *) dictionaryByMerging: (NSDictionary *) dict1 with: (NSDictionary *) dict2 {
NSMutableDictionary * result = [NSMutableDictionary dictionaryWithDictionary:dict1];
[dict2 enumerateKeysAndObjectsUsingBlock: ^(id key, id obj, BOOL *stop) {
if (![dict1 objectForKey:key]) {
[result setObject: obj forKey: key];
} else if ([obj isKindOfClass:[NSDictionary class]]) {
NSDictionary * newVal = [[dict1 objectForKey: key] dictionaryByMergingWith: (NSDictionary *) obj];
[result setObject: newVal forKey: key];
}
}];
return (NSDictionary *) [result mutableCopy];
}
I know this is an old question, but I need to do the same thing: recursively merge two dictionary objects. I need to go a step further and merge any objects that can be merged recursively (the end goal is merging two dictionaries created from plists). I am hosting my solution at https://github.com/bumboarder6/NSDictionary-merge
I am still working on the project, but as of this writing it already works (in limited testing) for recursive dictionary merging. Arrays and Sets are coming soon.
I noticed a few logic errors in some other solutions I have seen for this problem and I hopefully avoided those pitfalls, but critiques are welcome.
Usage is simple:
#import "NSMutableDictionary-merge.h"
NSMutableDictionary* dict1 = [NSMutableDictionary ...];
NSDictionary* dict2 = [NSDictionary ...];
[dict1 mergeWithDictionary:dict2];
#import "NSDictionary+Merge.h"
#implementation NSDictionary (Merge)
+ (NSDictionary *)dictionaryByMerging:(NSDictionary *)src with:(NSDictionary *)new
{
NSMutableDictionary *result = [src mutableCopy];
[new enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
if ([obj isKindOfClass:[NSDictionary class]]
&& [src[key] isKindOfClass:[NSDictionary class]]) {
result[key] = [src[key] dictionaryByMergingWith:obj];
} else {
result[key] = obj;
}
}];
return [NSDictionary dictionaryWithDictionary:result];
}
- (NSDictionary *)dictionaryByMergingWith:(NSDictionary *)dict {
return [[self class] dictionaryByMerging:self with:dict];
}
#end
I needed a way to recursively merge (append) objects within two JSON objects, focusing on the NSDictionaries within, but also considering NSArrays, and gracefully handling when types don't match along the way. The other answers here didn't go that far, and so I needed to write it myself. The following handles all those cases. Because the validation is at the top rather than in the middle it is usable starting with mixed nonnull and nullable objects. It could be expanded in the future to support additional types where appending may apply. To use, rename the xxx_ prefix to your own three digit prefix in lowercase. This is appropriate since this is an extension to a foundation class:
NSObject+Append.h
#interface NSObject (Append)
+ (nullable id)xxx_objectAppendingObject1:(nullable id)object1 object2:(nullable id)object2 NS_SWIFT_NAME(kva_objectAppending(object1:object2:));
#end
NSObject+Append.m
#implementation NSObject (Append)
+ (nullable id)xxx_objectAppendingObject1:(nullable id)object1 object2:(nullable id)object2
{
// VALIDATE ELSE RETURN
if (object1 == nil)
{
return object2;
}
if (object2 == nil)
{
return object1;
}
// MAIN
// dictionary1
NSDictionary *dictionary1 = [object1 isKindOfClass:NSDictionary.class] ? (NSDictionary *)object1 : nil;
// dictionary2
NSDictionary *dictionary2 = [object2 isKindOfClass:NSDictionary.class] ? (NSDictionary *)object2 : nil;
// array1
NSArray *array1 = [object1 isKindOfClass:NSArray.class] ? (NSArray *)object1 : nil;
// array2
NSArray *array2 = [object2 isKindOfClass:NSArray.class] ? (NSArray *)object2 : nil;
// A. NSDICTIONARY TO NSDICTIONARY
if ((dictionary1 != nil) && (dictionary2 != nil))
{
NSMutableDictionary *returnDictionary = dictionary1.mutableCopy;
[dictionary2 enumerateKeysAndObjectsUsingBlock: ^(id key, id obj, BOOL *stop)
{
returnDictionary[key] = [self.class kva_objectAppendingObject1:dictionary1[key] object2:obj];
}];
return returnDictionary;
}
// B. NSARRAY TO NSARRAY
if ((array1 != nil) && (array2 != nil))
{
return [array1.mutableCopy arrayByAddingObjectsFromArray:array2];
}
// DEFAULT
return object2;
}
#end

how to iterate nested dictionaries in objective-c iphone sdk

Hi I have a json string converted unsing the JSON framework into a dictionary and I need to extract its content. How could I iterate to the nested dictionaries? I have already this code that allows me to see the dictionary:
NSDictionary *results = [responseString JSONValue];
NSMutableArray *catArray = [NSMutableArray array];
for (id key in results) {
NSLog(#"key: %#, value: %#", key, [results objectForKey:key]);
[catArray addObject:key];
NSString *cat = key;
}
Could someone provide a sample on how to get to all the levels of the dic not using the name of the keys?
The result structure of the dic is like this: http://www.freeimagehosting.net/uploads/e7c020d697.png
alt text http://www.freeimagehosting.net/uploads/e7c020d697.png
thanks
ldj
You probably have to try recursive function.
-(void)recurse:(NSDictionary *)dict counter: (int*) i parent:(NSString *) parent{
for (NSString* key in [dict allKeys]) {
id value = [dict objectForKey:key];
NSLog(#"%# -> %#", parent, key);
if ([value isKindOfClass:[NSDictionary class]]) {
i++;
NSDictionary* newDict = (NSDictionary*)value;
[self recurse:newDict counter:i parent:key];
i--;
} else {
//Do smthg
}
}
}
this will list all keys and its level.
Try
for ((id) key in [results allKeys]) {
NSLog(#"key: %#, value: %#", key, [results objectForKey:key]);
[catArray addObject:key];
NSString *cat = key;
}
Hope that helped.
EDIT:
i'm not sure if i understand your structure correct, but i'm asuming you have some values in your dictionairy which are again dictionairies.
if you want to interate through a dictionairy which is located inside another one you could do it like this:
for ((id) key in [results allKeys]) {
id value = [results objectForKey:key];
if ([value isKindOfClass:[NSDictionary class]]) {
NSDictionary* newDict = (NSDictionary*)value;
for ((id) subKey in [newDict allKeys]) {
...
}
}
}
Of couse if you know the specific key to your desired dictionairy, you can check for that instead of checking if the value is a dict. But maybe it's not a bad idea to check that in both cases...
I'm sure you have solved this at this point, but I found it convenient to write a recursive utility class function that recursively logs every key of a dictionary:
/**
* Recursively logs the keys and values of each object in the dictionary,
* along with the class of the value.
*
* #param dict The dictionary to inspect
*/
+ (void)logDictionaryKeys:(NSDictionary*)dict {
for (id key in dict) {
if ([dict[key] isKindOfClass:[NSDictionary class]]) {
[self logDictionaryKeys:dict[key]];
}else {
NSLog(#"Key: %#", key);
NSLog(#"Value: %# (%#)", dict[key], [dict[key] class]);
}
}
return;
}
The header of the category:
#import <Foundation/Foundation.h>
#interface NSDictionary(Find)
-(id) findflat:(NSString*)keyToFind;
#end
The body:
#import "NSDictionary+Find.h"
#implementation NSDictionary(Find)
-(id) findflat:(NSString*)keyToFind{
if([self objectForKey:keyToFind])
return self[keyToFind];
for(id key in self)
if([[self objectForKey:key] isKindOfClass:[NSDictionary class]])
return [[self objectForKey:key] findflat:keyToFind];
return nil;
}
#end
Usage/Validation:
- (void)testExample {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct results.
NSDictionary *dic = #{};
XCTAssertNil([dic findflat:#"url"]);
dic = #{#"url":#"http://"};
XCTAssertEqual([dic findflat:#"url"],#"http://");
dic = #{#"other":#4};
XCTAssertNil([dic findflat:#"url"]);
dic = #{#"other":#4,#"url":#"http://"};
XCTAssertEqual([dic findflat:#"url"],#"http://");
dic = #{#"other":#4,#"sd":#"sdf"};
XCTAssertNil([dic findflat:#"url"]);
dic = #{#"other":#4,#"dic":#{#"url":#"http://"}};
XCTAssertEqual([dic findflat:#"url"],#"http://");
dic = #{#"other":#4,#"dic":#{#"sd":#2,#"url":#"http://"}};
XCTAssertEqual([dic findflat:#"url"],#"http://");
dic = #{#"other":#4,#"dic":#{}};
XCTAssertNil([dic findflat:#"url"]);
dic = #{#"other":#4,#"dic":#{#"dic":#{#"sd":#2,#"url":#"http://"}}};
XCTAssertEqual([dic findflat:#"url"],#"http://");
}
I have tried recursion and hope this could help.
P.S. This will return the first occurrence of the key.
+(id)getValue:(NSDictionary*)aDictionary forKey:(NSString *)aKey {
id finalValue = nil;
for (id key in [aDictionary allKeys]) {
id value = aDictionary[key];
if (value != nil && [key isEqualToString:aKey]) {
finalValue = value;
break;
}
else if ([value isKindOfClass:[NSDictionary class]]) {
finalValue = [[self class] getValue:value forKey:aKey];
}
}
return finalValue;
}