2012-02-13 15 views
7

C'è un modo tramite la notazione dei punti per accedere ai valori delle chiavi in ​​un NSDictionary come questo?Accesso a NSDictionary tramite notazione dot?

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

Dammi qualche minuto, creerò qualcosa che ti consentirà di usare la notazione punto usando una categoria. –

+4

@ 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. –

+1

Dubito che si possa fare qualcosa con sovrascrittura '- (id) valueForUndefinedKey:' poiché il compilatore rifiuterà il punto ... – JustSid

risposta

1

No, lo stai facendo nel modo corretto. Nel mondo iOS, spesso il modo corretto è l'unico modo. :)

Se si desidera realmente la notazione dei punti (e altre cose carine che si ottengono con gli oggetti digitati), si dovrà riempire la rappresentazione del dizionario in un oggetto. Più comunemente la mia interfaccia sarà simile:

@interface FooBar : NSObject { 
    NSString *someData; 
    int someNumber; 
} 

@property (nonatomic, copy) NSString *someData; 
@property (nonatomic, assign) int someNumber; 

+ (FooBar *)FooBarFromDictionary:(NSDictionary *)dataDict; 

@end 

L'applicazione dovrebbe essere chiaro. Quindi è possibile

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

Non tecnicamente.Puoi fare cose piuttosto folli con blocchi e categorie, dare un'occhiata alla mia risposta. –

1

No, non credo.

Dal manuale di riferimento.

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

Questo è elencato come l'unico modo per accedere alle chiavi e ai valori. Quindi lo stai facendo bene.

È possibile accedervi se le chiavi erano di proprietà pubblica ed erano leggibili.

6

Non c'è sintassi del punto per NSDictionary, ma dovrebbe considerare l'utilizzo di objectForKey: invece di valueForKey:

Difference between objectForKey and valueForKey?

+0

Grazie, lo farò, mi chiedevo quale fosse la differenza. Grazie per il link. – fuzzygoat

+0

+1 Questa risposta è più succinta della mia risposta, quindi cancellerò il mio a favore di questo. –

+0

@fuzzygoat nessun problema, spero che sia stato di aiuto. – kevboh

1

Il modo in cui si è accennato per l'accesso ai elemento di dizionario è il modo ideale (utilizzando i tasti). Se si vuole fare qualcosa di diverso, potrebbe essere che si può usare-

NSArray *allValues = [returnVal allValues]; 

Ora, usando questo array come pure è possibile eseguire attività. E se vuoi qualcosa di specifico, menzionalo, potrebbe essere per quello che può esserci un altro modo.

Anche come classe NSDictionary non è definita alcuna proprietà, pertanto la notazione dei punti non è direttamente possibile.

0

Tecnicamente, si può fare qualcosa di simile:

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; 
} 

Non so se questo è quello che stavi cercando, ma spero che aiuta!

+0

Non capisco perché qualcuno dovrebbe onestamente votare questo. Risponde a ciò che l'OP ha chiesto, come posso accedere a un dizionario con notazione a punti. Questo lo consente. –

+2

Questo è interessante ma in che modo si riferisce alla domanda di @ fuzzygoat? – benzado

+0

@ benzado perché gli permette di usare un NSDictionary con dot-notation, che è quello che voleva? –

5

Non proprio, no.

La notazione a punti è un modo abbreviato per chiamare un metodo con quel nome di selettore. In altre parole, questo ...

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

... è lo stesso di questo ...

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

quando dico "stesso", voglio dire che sono compilati verso il basso per lo stesso codice . È solo zucchero sintattico.

Un semplice NSDictionary non agirà in questo modo.Si potrebbe ordinare di esso falso con Codifica valore chiave, che ti permette di chiamare valueForKeyPath ottenere le proprietà in questo modo:

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

Se si voleva davvero essere in grado di scrivere foo.bar.name nel codice, tuttavia, si avrebbe dovuto crea una classe personalizzata che sostituisce forwardInvocation:; questo ti consente di catturare un messaggio sconosciuto su un oggetto e di fare qualcos'altro con esso oltre a generare un errore. In questo caso, è possibile modificare il selettore sconosciuto in una ricerca su un'istanza NSDictionary che contiene.

Ma anche se lo faceste, il compilatore probabilmente genererebbe ancora degli avvisi a meno che non abbiate creato i file di intestazione che hanno dichiarato quei nomi di proprietà esistenti.

3

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.

+0

[Downloadable [[h | m \] files] (https://gist.github.com/warpling/829e93a1357e9ef7f282) :) – Warpling

Problemi correlati