为什么没有通用的NSDictionary警告我关于错误输入的密钥插入/分配?

时间:2016-01-21 05:44:42

标签: objective-c generics

为什么以下NSDictionary / NSMutableDictionary来电不会产生错误或警告?

我预计会出现错误,因为rhs NSDictionary字面值与NSDictionary lhs局部变量的泛型类型不匹配。

NSDictionary<NSString *, NSNumber *> *foo = @{ @(42) : @"foo" };

我预计会出现错误,因为密钥类型与NSMutableDictionary的密钥泛型类型不匹配:

NSMutableDictionary<NSString *, NSNumber *> *foo = [NSMutableDictionary new];
// neither of these calls produces an error. :(
foo[@(42)] = @(42);
[foo setObject:@(42) forKey:@(42)];

当我尝试分配一个不正确类型的值时,我看到一个错误,所以我知道泛型错误在某种程度上有效:

NSMutableDictionary<NSString *, NSNumber *> *foo = [NSMutableDictionary new];
foo[@"foo"] = @"bar";

导致以下警告:

Foo.m:81:16: Incompatible pointer types sending 'NSString *' to parameter of type 'NSNumber * _Nullable'

为什么不进行字面分配或键入不正确的密钥会导致警告/错误?

I filed this as a radar.

1 个答案:

答案 0 :(得分:3)

似乎这是编译器的限制/错误,由setObject:forKeyedSubscript:方法的定义引起:

- (void)setObject:(nullable ObjectType)obj forKeyedSubscript:(KeyType <NSCopying>)key;

协议符合要求以某种方式隐藏了KeyType的类型要求。如果<NSCopying>不存在,则编译器会进行KeyType检查并发出警告。

为了确认这一点,我玩了一些代码,结果如下:

@interface MyDictionary<KeyType, ObjectType>: NSObject    
- (void)setObject:(nullable ObjectType)obj forKeyedSubscript:(KeyType <NSCopying>)key;
@end

...

MyDictionary<NSNumber*, NSNumber*>* dict = [[MyDictionary alloc] init];
UIButton *button = [[UIButton alloc] initWithFrame:CGRectZero];
dict[@"98"] = @14; // no warnings
dict[button] = @14; //warning: Sending 'UIButton *' to parameter of incompatible type 'id<NSCopying>'

上述代码与NSMutableDictionary具有相同的行为。但是,如果我删除<NSCopying>的{​​{1}}协议一致性限制,那么编译器会给出相应的警告:

KeyType

注意。默认情况下,您会收到有关对象类型不匹配的警告,如果您希望收到错误,可以启用@interface MyDictionary<KeyType, ObjectType>: NSObject - (void)setObject:(nullable ObjectType)obj forKeyedSubscript:(KeyType)key; @end ... MyDictionary<NSNumber*, NSNumber*>* dict = [[MyDictionary alloc] init]; dict[@"98"] = @14; // warning: Incompatible pointer types sending 'NSString *' to parameter of type 'NSNumber *' 版本设置,或只启用{ {1}}一个。