abbood
abbood

Reputation: 23548

a faster way to mutate an Array of NSMutableDictionaries

based on the fact that you cannot edit mutable Collections while enumerating them, this is the best solution i could come up with to edit a Array of NSMutableDictionaries:

__block NSMutableDictionary *tempDict = [NSMutableDictionary dictionaryWithCapacity:1];
__block NSUInteger idx;
[_myArray enumerateObjectsUsingBlock:^(NSMutableDictionary* obj, 
                                                        NSUInteger indx, BOOL *stop) {
    if (// some condition is met) {
        tempDict = [obj mutableCopy];
        idx = indx;
    }
}];

[tempDict setObject:[NSNumber numberWithInt:thisQueryResults] forKey:@"resultsNum"];
[_myArray replaceObjectAtIndex:idx withObject:rowSelected];

this seems way too complicated (even for a language like obj-c).. and since it's involving two data types (NSMutableArray and NSMutableDictionary), it doesn't seem like I can cleanly put them into a category.. advice?

update: one comment asked why do I create a mutablecopy (as opposed to just a copy.. since it's copying a mutable object)..

suppose I just used copy.. if i put a break on tempDict this is what I get:

// tempDict = [obj copy]
po tempDict
$0 = 0x0b28cc10 <__NSArrayI 0xb28cc10>(
1
)

// tempDict = [obj mutableCopy]
po tempDict
$0 = 0x0b28cc10 <__NSArrayM 0xb28cc10>( //notice the M in __NSArrayM as opposed to I above
1
)

in case of copy.. if I follow it with a line like this: [tempDict setObject:[NSNumber numberWithInt:thisQueryResults] forKey:@"resultsNum"];

I get this error:

[__NSDictionaryI setObject:forKey:]: unrecognized selector sent to instance 0xb245100

I get the same above error with this code:

for (NSUInteger idx = 0; idx < [_myMutableArray count]; idx++) {
    NSMutableDictionary* myMutableDict = _myMutableArray[idx];
    [myMutableDict setObject:obj forKey:key];        
}

update 2: the origin of the problem was instantiating non mutable arrays and dictionaries.. I'm new to the whole new obj-c literals, so I didn't know that to create a NSMutableArray and NSDictionary, you gotta do this, respectively:

[@[..] mutableCopy]
[@{..} mutableCopy]

Upvotes: 1

Views: 175

Answers (3)

iPav
iPav

Reputation: 101

Maybe you can use KVC and do :

NSArray<NSMutableDictionary *> *result = [[_myArray filteredArrayUsingPredicate:[NSPredicate withFormat:@"{YOUR CONDITION}"]] valueForKey:@"mutableCopy"];

Upvotes: 0

steipete
steipete

Reputation: 7641

So in your case, I don't quite follow why you call tempDict = [obj mutableCopy]; when from the conditions you write the dictionary is already writable.

You can use several tricks. Like using

for (NSUInteger idx = 0; idx < _myArray.count: idx++_ {
   NSMutableDictionary *obj = _myArray[idx];

  // modify
}

For NSDictionaries you can get allKeys and iterate over that copy. This is a bit slower than using fast enumeration, but still faster than doing workarounds like boxing integers to replace later :)

Upvotes: 1

aLevelOfIndirection
aLevelOfIndirection

Reputation: 3522

In your case you are NOT modifying the array at all only the dictionaries within the array. There are no contstraits on how you modify the objects within the array. Here is a bit of equivalent code:

for (NSMutableDictionary *dict in _myArray) {
    if (someCondition)
         [dict setObject:[NSNumber numberWithInt:thisQueryResults] forKey:@"resultsNum"]
}

You would have a problem if you absolutely needed to replace the object in your array. In that case, if the array is not huge I would suggest the same as @Markus. Iterate over a copy and modify the original.

Upvotes: 1

Related Questions