2012-02-13 2 views
7

Есть ли способ через точечную нотацию для доступа к значениям ключей в NSDictionary, как это?Доступ к NSDictionary через точную нотацию?

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

Дайте мне несколько минут, я сделаю что-то, что позволит вам использовать точечную нотацию, используя категорию. –

+4

@ RichardJ.RossIII Я не думаю, что вы должны отвечать категорией. Это демонстрирует некоторые возможности Obj-C, но для этого было бы довольно плохой практикой. Возможно, лучшим вариантом будет предложить объект модели, который является подклассом «NSObject». –

+1

Я сомневаюсь, что вы можете что-то сделать с перезаписью '- (id) valueForUndefinedKey:' поскольку компилятор отклонит точку ... – JustSid

ответ

1

Нет, вы делаете это правильно. В мире iOS часто правильный путь - единственный способ. :)

Если вам действительно нужна точечная нотация (и другие приятные вещи, которые вы получаете с типизированными объектами), вам придется заполнить представление словаря в объект. Чаще всего мой интерфейс будет выглядеть так:

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

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

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

@end 

Реализация должна быть ясной. Тогда вы можете

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

Не технически.Вы можете сделать довольно сумасшедшие вещи с блоками и категориями, заглянуть в мой ответ. –

1

Нет, я так не думаю.

Из справочного руководства.

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

Это указано как единственный способ доступа к ключам и значениям. Таким образом, вы делаете это хорошо.

Вы могли бы получить к нему доступ, если бы ключи были общедоступными и были доступны для чтения.

6

Там нет точки синтаксис NSDictionary, но следует использовать objectForKey: вместо valueForKey:

Difference between objectForKey and valueForKey?

+0

Спасибо, я сделаю это, мне было интересно, какая разница. Спасибо за ссылку. – fuzzygoat

+0

+1 Этот ответ более краткий, чем мой ответ, поэтому я собираюсь удалить мои в пользу этого. –

+0

@fuzzygoat никаких проблем, надеюсь, что это помогло. – kevboh

1

То, как вы уже упоминали для доступа к элементу словаря идеальный способ (с помощью клавиши). Если вы хотите сделать что-то еще, может быть, вы можете потребительных

NSArray *allValues = [returnVal allValues]; 

Теперь, используя этот массив, а также вы можете выполнять задачи. И если вы хотите что-то конкретное, то укажите, что, возможно, для этого может быть и другой способ.

Кроме того, поскольку класс NSDictionary не будет обладать каким-либо определенным свойством, то обозначение точки напрямую невозможно.

0

Технически, вы можете сделать что-то вроде этого:

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

Я не знаю, если это то, что вы искали, но я надеюсь, что это помогает!

+0

Я не понимаю, почему кто-то честно проголосовал бы за это. Он отвечает тем, что спросил ОП, как я могу получить доступ к словарю с точечной нотацией. Это позволяет. –

+2

Это интересно, но как это связано с вопросом @ fuzzygoat? – benzado

+0

@ benzado, потому что он позволяет ему использовать NSDictionary с точечной нотацией, чего он хотел? –

5

Не совсем, нет.

Точечная нотация - это сокращенный способ вызова метода с этим именем селектора. Другими словами, это ...

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

... так же, как это ...

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

Когда я говорю «же», я имею в виду, они составлены до того же кода , Это просто синтаксический сахар.

Обычный NSDictionary не будет действовать таким образом.Вы можете сортировать поддельный его с Key Value Coding, который позволяет назвать valueForKeyPath получить свойства, как это:

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

Если вы действительно хотите, чтобы иметь возможность написать foo.bar.name в коде, однако, вы должны были бы создать пользовательский класс, который переопределяет forwardInvocation:; это позволяет вам поймать неизвестное сообщение объекту и сделать что-то еще с ним, кроме того, чтобы выбросить ошибку. В этом случае вы можете изменить неизвестный селектор на поиск в экземпляре NSDictionary, который он содержит.

Но даже если вы это сделали, компилятор, вероятно, все еще генерирует предупреждения, если вы не создали заголовочные файлы, которые объявили имена этих свойств.

3

Я согласен с большинством ответов, что NSDictionary должен быть доступен с помощью objectForKey: или аналогичными методами. Однако можно разрешить доступ к точкам нотации к NSDictionary, и для учебных целей это может быть интересно для кого-то. Также, когда вы, например, получаете большие словари JSON через AFNetworking, этот метод может облегчить доступ и читаемость вашего кода.

Это мое решение:

DictionaryProperties.h: (класс обертывание NSDictionary для доступа к свойству)

@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: (класс объявление внутри словаря)

#import "DictionaryProperties.h" 

@interface ExampleDictContent : DictionaryProperties 

@property (strong, nonatomic) NSString* someData; 
@property (strong, nonatomic) NSString* someOtherData; 

@end 

@implementation ExampleDictContent 
@end 

Использование: (простая декларация словаря, выделение обертки и доступ к свойству)

#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); 

Это будет печатать:

someData content 
someOtherData content 

Так в основном DictionaryProperties работы в качестве фасада для доступа к NSDictionary. Он использует forwardInvocation для преобразования метода вызова get-property в вызов getObjectForKey: по словарю. Что мне нравится в этом, так это то, что он позволяет автозаполнение словаря, а также позволяет явным образом объявлять, какие ключи я хочу получить (в файле ExampleDictContent.h). Обратите внимание, что это решение не позволяет писать права доступа к свойствам, но может быть добавлено, как показано в приведенной ниже ссылке.

Это решение частично вдохновлено karstenlitsche's solution. Основное отличие состоит в том, что это решение основано на подклассификации вместо категорий.

+0

[Загружаемые \ [ч | т \] файлы] (https://gist.github.com/warpling/829e93a1357e9ef7f282) :) – Warpling

Смежные вопросы