Sono d'accordo con la maggior parte delle risposte a cui è necessario accedere NSDictionary
con objectForKey:
o metodi simili. Tuttavia è possibile consentire l'accesso alla notazione di punti a NSDictionary
e, a fini di apprendimento, potrebbe essere interessante per qualcuno. Anche quando, ad esempio, stai recuperando dizionari JSON di grandi dimensioni tramite AFNetworking
, questo metodo può facilitare l'accesso e la leggibilità del tuo codice.
Questa è la mia soluzione:
DictionaryProperties.h: (classe avvolgendo il NSDictionary per l'accesso di proprietà)
@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: (classe che dichiara cosa c'è dentro il dizionario)
#import "DictionaryProperties.h"
@interface ExampleDictContent : DictionaryProperties
@property (strong, nonatomic) NSString* someData;
@property (strong, nonatomic) NSString* someOtherData;
@end
@implementation ExampleDictContent
@end
Usage: (semplice dichiarazione di un dizionario, assegnazione di involucro e l'accesso alle proprietà)
#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);
Questo stamperà:
someData content
someOtherData content
Quindi, in pratica DictionaryProperties
opere come una facciata per l'accesso al NSDictionary
. Utilizza forwardInvocation
per convertire una chiamata di metodo get-property
in una chiamata getObjectForKey:
sul dizionario. Quello che mi piace, è che consente il completamento automatico sul dizionario e mi permette anche di dichiarare esplicitamente a quali chiavi voglio accedere (nel file ExampleDictContent.h
). Si noti che questa soluzione non consente l'accesso in scrittura alle proprietà, ma può essere aggiunto come mostrato nel link sottostante.
Questa soluzione è stata parzialmente ispirata allo karstenlitsche's solution. La differenza principale è che questa soluzione si basa sulla sottoclassificazione anziché sulle categorie.
Dammi qualche minuto, creerò qualcosa che ti consentirà di usare la notazione punto usando una categoria. –
@ RichardJ.RossIII Non penso che dovresti rispondere con una categoria. Mostra alcune capacità Obj-C, ma sarebbe una pratica piuttosto negativa per questo. Forse suggerire un oggetto modello che sia una sottoclasse di 'NSObject' sarebbe un approccio migliore. –
Dubito che si possa fare qualcosa con sovrascrittura '- (id) valueForUndefinedKey:' poiché il compilatore rifiuterà il punto ... – JustSid