简体   繁体   中英

'-setValue:forKey:' exception when updating the fields of an NSMutableDictionary

I have two NSMutableDictionary objects called "dict" and newdict. Then try to assign newdict to the "myfield1" field. However, I'm facing an error.

NSMutableDictionary *dict = @{ @"myfield1" : @{  @"subfield1" : @"mysubfield1" ,
                                           @"subfield2" : @"mysubfield2" },
                              @"myfield2": @"myfield2",
                              @"myfield3": @"myfield3"};
NSMutableDictionary *newdict =  @{  @"subfield1" : @"mynewsubfield1" ,
                                    @"subfield2" : @"mynewsubfield2" };

[dict setValue:newdict forKey:@"myfield1"];

Error:

*** Terminating app due to uncaught exception 'NSUnknownKeyException', 
reason: '[<__NSDictionaryI 0x17db3bb0> setValue:forUndefinedKey:]: 
this class is not key value coding-compliant for the key loc.'

How can I solve this problem?

Don't use setValue:forKey: as this is a KVC method, not a dictionary method. Use setObject:forKey: . Technically the KVC method will work, but you should generally only use it when you have a specific need to.

Your real problem is that your dictionary instances aren't mutable. Use mutableCopy to create mutable versions from your literal definitions. Literal definitions are always immutable.

As explained by @Wain, your dictionary instances aren't mutable.

What may be confusing to you is that you declare the variables as NSMutableDictionary so you think they will be mutable. But the @{ … } literal syntax is equivalent to [NSDictionary dictionaryWithObjects:forKeys:count: , thus creating a (non-mutable) NSDictionary instance .

The fact that you affect this value to a variable of type NSMutableDictionary does not change this and does not make this dictionary magically mutable.

That's why @Wain correctly suggested to use mutableCopy to make this NSDictionary an NSMutableDictionary so you can call setValue:forKey: or setObject:forKey: on it. Another way would be to use [NSMutableDictionary dictionaryWithDictionary:@{ … }]; to create your mutable dictionary.


In fact, if the -Wincompatible-pointer-types warning is ON, which should be the case by default, you should have a warning like warning: incompatible pointer types initializing 'NSMutableDictionary *' with an expression of type 'NSDictionary *' which should have led you to the cause of your problem and its solution. (Always read the warnings, that's not because they are only warnings and they don't make the compilation fail that they are not important!)

Just add "mutableCopy" to make your dictionary of type NSMutableDictionary

NSMutableDictionary *dict = [@{ @"myfield1" : @{  @"subfield1" : @"mysubfield1" ,
                                                     @"subfield2" : @"mysubfield2" },
                                   @"myfield2": @"myfield2",
                                   @"myfield3": @"myfield3"} mutableCopy];

NSMutableDictionary *newdict =  [@{  @"subfield1" : @"mynewsubfield1" ,
                                        @"subfield2" : @"mynewsubfield2" } mutableCopy];


dict[@"myfield1"]=newdict;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM