I agree with most of the answers that NSDictionary
should be accessed with objectForKey:
or similar methods. However it is possible to allow for dot notation access to a NSDictionary
, and for learning purposes this might be interesting for someone. Also when for example your are retrieving large JSON dictionaries via AFNetworking
, this method can ease the access and readability of your code.
This is my solution:
DictionaryProperties.h: (class wrapping the NSDictionary for property access)
@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 declaration of a dictionary, allocation of wrapper and property access)
#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
So basically DictionaryProperties
works as a facade for accessing the NSDictionary
. It uses forwardInvocation
to convert a get-property
method call into a getObjectForKey:
call on the dictionary. What I like about it, is that it allows for autocompletion on the dictionary, and also allows me to explicitly declare what keys I want to access (in the ExampleDictContent.h
file). Note that this solution does not allow for write access to the properties, but that can be added as shown in the link below.
This solution has partly been inspired by karstenlitsche's solution. The main difference is that this solution is based on sub-classing instead of categories.