Access NSDictionary through dot notation?

Is there a way through dot notation to access key values ​​in an NSDictionary like this?

NSDictionary *returnVal = [NSDictionary dictionaryWithObjectsAndKeys:@"Saturn", @"name", @"Gas Giant", @"type", nil]; NSLog(@"VALUE: %@", [returnVal valueForKey:@"name"]); // This is how I am doing it now. 
+7
source share
7 answers

There is no point syntax for NSDictionary , but you should use objectForKey: instead of valueForKey:

Difference between objectForKey and valueForKey?

+6
source

Not really, no.

Dot notation is an abbreviated way to call a method with this selector name. In other words, this is ...

 NSLog(@"Hello, %@", foo.bar.name); 

... the same as ...

 NSLog(@"Hello, %@", [[foo bar] name]); 

When I say the same thing, I mean that they are compiled to the same code. It is just syntactic sugar.

A regular NSDictionary will not act this way. You can fake it with Key Value Coding, which allows you to call valueForKeyPath to get these properties:

 NSLog(@"Hello, %@", [foo valueForKeyPath:@"bar.name"]); 

If you really wanted to write foo.bar.name in your code, you must create your own class that overrides forwardInvocation: this allows you to catch an unknown message to the object and do something else with it, in addition to throwing an error. In this case, you can change the unknown selector to search in the NSDictionary instance that it contains.

But even if you do, the compiler will probably still generate warnings if you did not create header files that declared the names of these properties.

+5
source

I agree with most of the answers NSDictionary should NSDictionary with objectForKey: or similar methods. However, you can allow access to the notation points to NSDictionary , and for training this may be interesting for someone. Also, when you, for example, get large JSON dictionaries through AFNetworking , this method can facilitate the access and readability of your code.

This is my decision:

DictionaryProperties.h: (a class that carries an NSDictionary for accessing properties)

 @interface DictionaryProperties : NSObject{ NSMutableDictionary* _backingDict; } @property (nonatomic, strong) NSMutableDictionary* backingDict; + (DictionaryProperties*) allocWithDictionary:(NSDictionary*)dict; @end 

DictionaryProperties.m:

 #import "DictionaryProperties.h" @implementation DictionaryProperties @synthesize backingDict = _backingDict; - (id) initWithDictionary:(NSDictionary*)dict { if (self) { if ([dict isKindOfClass:[NSMutableDictionary class]]) { self.backingDict = (id)dict; } else { self.backingDict = [[NSMutableDictionary alloc] initWithDictionary:dict]; } } return self; } + (DictionaryProperties*) allocWithDictionary:(NSDictionary*)dict { return [[DictionaryProperties alloc] initWithDictionary:dict]; } - (void)forwardInvocation:(NSInvocation *)invocation { NSString* key = NSStringFromSelector(invocation.selector); invocation.selector = @selector(objectForKey:); [invocation setArgument:&key atIndex:2]; if ([self.backingDict objectForKey:key]) { [invocation invokeWithTarget:self.backingDict]; } else { [self doesNotRecognizeSelector:invocation.selector]; } } - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{ return [self.backingDict methodSignatureForSelector:@selector(objectForKey:)]; } @end 

ExampleDictContent.h: (class declaring what is inside the dictionary)

 #import "DictionaryProperties.h" @interface ExampleDictContent : DictionaryProperties @property (strong, nonatomic) NSString* someData; @property (strong, nonatomic) NSString* someOtherData; @end @implementation ExampleDictContent @end 

Usage: (simple dictionary declaration, shell distribution, and access to properties)

 #import "ExampleDictContent.h" NSDictionary* d = [NSDictionary dictionaryWithObjects:NSArray arrayWithObjects:@"someData content", @"someOtherData content", nil forKeys:NSArray arrayWithObjects:@"someData", @"someOtherData", nil]; ExampleDictContent* dictWProps = [ExampleDictContent allocWithDictionary:d]; NSLog(dictWProps.someData); NSLog(dictWProps.someData); 

This will print:

 someData content someOtherData content 

Thus, basically DictionaryProperties acts as a facade for accessing NSDictionary . It uses forwardInvocation to convert a call to the get-property method to a call to getObjectForKey: in the dictionary. I like the fact that it allows autocompletion of the dictionary, and also allows you to explicitly declare which keys I want to receive (in the ExampleDictContent.h file). Please note that this solution does not allow write access to properties, but can be added as shown in the link below.

This solution is partly inspired by the karstenlitsche solution . The main difference is that this decision is based on subclassification instead of categories.

+3
source

No, you are doing it right. In the iOS world, often the right way is the only way. :)

If you really need dot notation (and other nice things you get with typed objects), you will have to fill out the dictionary view into the object. Most often, my interface will look like this:

 @interface FooBar : NSObject { NSString *someData; int someNumber; } @property (nonatomic, copy) NSString *someData; @property (nonatomic, assign) int someNumber; + (FooBar *)FooBarFromDictionary:(NSDictionary *)dataDict; @end 

Implementation must be clear. Then you can

 FooBar *fb = [FooBar FooBarFromDictionary:data]; NSLog(@"fb.someData = %@", fb.someData); 
+1
source

No, I do not think so.

From the reference guide.

 Accessing Keys and Values – allKeys – allKeysForObject: – allValues – getObjects:andKeys: – objectForKey: – objectsForKeys:notFoundMarker: – valueForKey: 

This is indicated as the only way to access keys and values. So you do it well.

You could access it if the keys were public and readable.

+1
source

What you mentioned for accessing a dictionary item is an ideal way (using keys). If you want to do something else, maybe you can use -

 NSArray *allValues = [returnVal allValues]; 

Now, using this array, you can perform tasks. And if you want something specific, then indicate that there may be another way for this.

Furthermore, since the NSDictionary class will not have any properties, point-to-point is not directly possible.

+1
source

Technically, you can do something like this:

 typedef id (^valueBlock)(id); @interface NSDictionary(dotNotationAddons) @property(nonatomic, readonly) valueBlock value; @end @implementation NSDictionary(dotNotationAddons) -(valueBlock) value { return [[^(id key) { return [self objectForKey:key]; } copy] autorelease]; } @end int main (int argc, const char * argv[]) { @autoreleasepool { NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:@"1", @"One", @"2", @"Two", @"3", @"Three", @"4", @"Four", nil]; id value = dictionary.value(@"One"); NSLog(@"%@", value); } return 0; } 

I don’t know, this is what you were looking for, but I hope this helps!

0
source

All Articles