有没有办法通过点表示法来访问像这样的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 :(得分:6)
NSDictionary
没有点语法,但应考虑使用objectForKey:
代替valueForKey:
答案 1 :(得分:5)
不是,不。
点表示法是使用该选择器名称调用方法的简便方法。换句话说,这......
NSLog(@"Hello, %@", foo.bar.name);
......与此相同......
NSLog(@"Hello, %@", [[foo bar] name]);
当我说“相同”时,我的意思是它们被编译成相同的代码。这只是语法糖。
普通的NSDictionary不会这样做。您可以使用键值编码来伪造它,这可以让您调用valueForKeyPath
来获取这样的属性:
NSLog(@"Hello, %@", [foo valueForKeyPath:@"bar.name"]);
但是,如果您真的希望能够在代码中编写foo.bar.name
,则必须创建一个覆盖forwardInvocation:
的自定义类;这可以让你捕获一个未知的消息给一个对象,并用它做其他事情,除了抛出一个错误。在这种情况下,您可以将未知选择器更改为它包含的NSDictionary实例上的查找。
但即使您这样做,编译器仍可能会生成警告,除非您创建了声明这些属性名称的头文件。
答案 2 :(得分: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
的外观。它使用forwardInvocation
将get-property
方法调用转换为字典上的getObjectForKey:
调用。我喜欢它的是,它允许在字典上自动完成,并且还允许我显式声明我想要访问的键(在ExampleDictContent.h
文件中)。请注意,此解决方案不允许对属性进行写入访问,但可以添加,如下面的链接所示。
此解决方案部分受到karstenlitsche's solution的启发。主要区别在于此解决方案基于子类而不是类别。
答案 3 :(得分: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);
答案 4 :(得分:1)
不,我不这么认为。
参考手册。
Accessing Keys and Values
– allKeys
– allKeysForObject:
– allValues
– getObjects:andKeys:
– objectForKey:
– objectsForKeys:notFoundMarker:
– valueForKey:
这被列为访问密钥和值的唯一方法。所以你做得很好。
如果密钥是公共属性且可读,则可以访问它。
答案 5 :(得分:1)
您提到的访问字典元素的方式是理想的方法(使用键)。 如果你想做别的事,你可以使用 -
NSArray *allValues = [returnVal allValues];
现在使用此数组也可以执行任务。 如果你想要特定的东西然后提一下,可能是因为可以有其他方式。
同样由于NSDictionary类没有定义任何属性,因此点符号是不可能的。
答案 6 :(得分: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;
}
我不知道这是不是你想要的,但我希望它有所帮助!
答案 7 :(得分:0)
答案仍然没有,但是您可以使用速记
myDictionary[@"key"]
代替
[myDictionary objectForKey:@"key"]
答案 8 :(得分:0)
在Swift中,有一个解决方案看似不太优雅,但却可以解决问题。
对于每种特定类型的Dictionary,它都需要一个typeAlias;对于字典中的每个预期键,都需要一个带有变量的扩展名(带有getter / setter)。根本不是一个好习惯
以相同的方式将dict对象包装到对象(类/结构)中可能会更容易。
typealias MyDict = [String:AnyObject]
extension MyDict {
var key: AnyObject? {
get { return self["key"] }
set { self["key"] = newValue }
}
}
// Usage
var myDict = MyDict()
// Get the value
myDict["key"] = "value1" as AnyObject
if let str = myDict.key {
print(str) // prints "value1"
}
// Set the value
myDict.key = "value2" as AnyObject
if let str = myDict["key"] {
print(str) // prints "value2"
}