KarlJay
KarlJay

Reputation: 79

setObject: forKey: crashes when used on multi-dim NSMuteableDictionary

I have an NSMutableDictionary and inside that I have an series of elements for sections. I need to change one of those elements in the sub section.

So I make an NSMutableDictionary from the object returned, I want to modify that, then replace that inside the main NSMutableDictionary.

        int intTagToFind = 1;
        NSLog(@"Finding tag %u",intTagToFind);
        for (int i=0; i < returnDict.count; i++){
            NSString *keyString = [NSString stringWithFormat: @"section%03d",i];
            NSMutableDictionary *sectionData = [returnDict objectForKey:keyString];
            for (int j=0; j<sectionData.count; j++) {
                int myTag = [[sectionData objectForKey:@"tag"] intValue];
                if (myTag == intTagToFind){
                    NSLog(@"Found Tag: %u %u",myTag,intTagToFind);
                    NSLog(@"Key to finding is %@",keyString);
                    NSLog(@"Header is:%@",[sectionData objectForKey:@"section header"]);
                    NSLog(@"Class: %@",[sectionData class]);
                    NSLog(@"Class: %@",[returnDict class]);


[sectionData setObject:@"new header here" forKey:@"section header"];
                    NSLog(@"New Header is:%@",[sectionData objectForKey:@"section header"]);

                }
            }
        }

It gives: [__NSDictionaryI setObject:forKey:]: unrecognized selector sent to instance 0x7f9414110080

When I create sectionData with: NSMutableDictionary *sectionData = [returnDict objectForKey:keyString];

It's returning class name as __NSDictionaryI while the returnDict is class name: __NSDictionaryM

Why is it giving me the wrong type? Can you not get a muteable dictionary from objectForKey ?

Here's the code that converts the array into the dictionary:

NSMutableDictionary *returnDict = [[NSMutableDictionary alloc] init];
for(int i=0; i < [returnData count] - 1; i++)
{
    [returnDict setObject:[returnData objectAtIndex:i+1] forKey:[NSString stringWithFormat: @"section%03d", i]];
}

And here's a sample of what the array looks like:

NSArray *returnData = @[ @{ @"section header": @"Business News",
                                        @"sub header": @"Investing news",
                                        @"sub header scroll": @"0",
                                        @"sub button": @"Delete",
                                        @"tag":@"0",
                                        @"articles": @[ @{ @"title": @"One" },
                                                        @{ @"title": @"Longer" },
                                                        @{ @"title": @"Even Longer" },
                                                        @{ @"title": @"Still Much Longer" },
                                                        @{ @"title": @"Really Long Title Here Now." }
                                                        ]
                                        },

I'm using 'tag' as a unique id.

I create the array, load the array into the dictionary, then want to change elements inside like header, button, etc... using tag as the unique id.

Upvotes: 0

Views: 466

Answers (1)

Duncan C
Duncan C

Reputation: 131481

This code:

NSMutableDictionary *sectionData = [returnDict objectForKey:keyString];

Does not create a mutable dictionary. It fetches whatever is in returnDict at the key keyString and CASTS it to NSMutableDictionary type. The underlying object doesn't change.

You actually have shared ownership of the object from returnDict at that point. If the object is immutable inside returnDict, it will remain immutable.

You probably want to do this:

NSDictionary *immutableSectionData = [returnDict objectForKey:keyString];
NSMutableDictionary *sectionData = [immutableSectionData mutableCopy];

(The code above is broken into 2 lines simply to make it easy to read in the narrow SO text view.)

EDIT:

In fact, if the second code block in your post is how you are creating your data structure, the entire thing is immutable. You won't be able to change any of it.

Upvotes: 1

Related Questions