通过点表示法访问NSDictionary?

问题描述 投票:7回答:8

有没有办法通过点表示法来访问像这样的NSDictionary中的键值?

NSDictionary *returnVal = [NSDictionary dictionaryWithObjectsAndKeys:@"Saturn", @"name", @"Gas Giant", @"type", nil];
NSLog(@"VALUE: %@", [returnVal valueForKey:@"name"]); // This is how I am doing it now.
iphone objective-c nsdictionary
8个回答
6
投票

NSDictionary没有点语法,但应考虑使用objectForKey:而不是valueForKey:

Difference between objectForKey and valueForKey?


5
投票

不是,不是。

点表示法是使用该选择器名称调用方法的简便方法。换句话说,这......

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

......跟这个一样......

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

当我说“相同”时,我的意思是它们被编译成相同的代码。这只是语法糖。

一个普通的NSDictionary不会这样做。您可以使用键值编码来伪装它,它可以让您调用valueForKeyPath来获取这样的属性:

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

但是,如果您真的希望能够在代码中编写foo.bar.name,那么您必须创建一个覆盖forwardInvocation:的自定义类;这可以让你捕获一个未知的消息给一个对象,并用它做其他事情,除了抛出一个错误。在这种情况下,您可以将未知选择器更改为它包含的NSDictionary实例上的查找。

但即使您这样做,编译器仍可能会生成警告,除非您创建了声明这些属性名称的头文件。


3
投票

我同意NSDictionary应该使用objectForKey:或类似方法访问的大多数答案。然而,有可能允许点符号访问NSDictionary,并且出于学习目的,这可能对某人有趣。此外,例如,当您通过AFNetworking检索大型JSON字典时,此方法可以简化代码的访问和可读性。

这是我的解决方案:

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的外观。它使用forwardInvocationget-property方法调用转换为字典上的getObjectForKey:调用。我喜欢它的是,它允许在字典上自动完成,还允许我明确声明我想要访问的键(在ExampleDictContent.h文件中)。请注意,此解决方案不允许对属性进行写入访问,但可以添加,如下面的链接所示。

这个解决方案部分受到karstenlitsche's solution的启发。主要区别在于此解决方案基于子类而不是类别。


1
投票

不,我不这么认为。

从参考手册。

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

这被列为访问密钥和值的唯一方法。所以你做得很好。

如果密钥是公共属性并且可读,则可以访问它。


1
投票

您提到的访问字典元素的方式是理想的方式(使用键)。如果你想做别的事,也许你可以用 -

NSArray *allValues = [returnVal allValues];

现在使用此数组也可以执行任务。如果你想要一些特定的东西然后提一下,可能是因为可以有其他方式。

此外,由于NSDictionary类不会定义任何属性,因此点符号是不可能的。


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
投票

从技术上讲,你可以这样做:

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
投票

答案仍然没有,但你可以使用速记

myDictionary[@"key"]

代替

[myDictionary objectForKey:@"key"]
© www.soinside.com 2019 - 2024. All rights reserved.