I want to use valueForKeyPath
on my NSDictionary
, but the problem is that one of the keys is a string that starts with the @ symbol. I have no cont
you shouldn't be using @ signs with your key names if you want to use key value coding.
apple's guidelines for key names are as follows:
Keys must use ASCII encoding, begin with a lowercase letter, and may not contain whitespace.
You'll have to find a workaround to reformat the key string whereever you're getting your keys from to be KVC compliant.
If you have no control over the naming, how about adding a category with a properly named key that simply returns/sets the weird key?
In my humble opinion, the whole discussion here goes the wrong way Accessing entries in an NSDictionary via key paths - is simply not part of KVC protocol.
KVC defines how to name your properties of an object, so that KVC can work. an entry in an NSDictionary is not a property, and has no name. NSDictionary adds its bit of magic to the KVC-like behaviour, by "pretending" the keys of its entries are like 'properties' of the dictionary.
Alas, properties have different naming conventions and limitations than dictionary keys.
If you cannot force the dictionary keys to conform with KVC-supported property names - break your key paths, and use the accessors instead where in doubt.
That, I think, should be the safest way to go. KVC is generally a "nicety" being able to shorten your code - but it does NOT provide any functionality you cannot have otherwise (as you demonstrated yourself).
I see that there are 2 ways
Swizzle
You can swizzle the valueForKeyPath
on NSDictionary
to remove the @ symbol, remember to account for @sum, @average, ...
Override if you're using Mantle
Override + (id)modelOfClass:(Class)modelClass fromJSONDictionary:(NSDictionary *)JSONDictionary
on MTLJSONAdapter
, traverse all the keys and remove the @ symbol
Just to update this old question a little...
The reason that these:
[dict valueForKeyPath:@"key1.@specialKey.key3"]
[dict valueForKeyPath:@"key1.@@specialKey.key3"]
...fail is that any "@" symbols in a key path are interpreted as being collection's operators as with:
[dict valueForKeyPath:@"key1.@sum.key3"] // returns the sum of all 'key3' values
[dict valueForKeyPath:@"key1.@avg.key3"] // returns the average of all 'key3' values
The nested key calls:
[[[dict objectForKey:@"key1"] objectForKey:@"@specialKey"] objectForKey:@"key3"]
... work because a single key is not processed as a key path.