2016-01-21 15 views
3

为什么以下NSDictionary/NSMutableDictionary调用会产生错误或警告?为什么通用NSDictionary不会提示有关错误键入的键/赋值?

我期望在这里出现错误,因为rhs NSDictionary文字不符合012hlhs局部变量的通用类型。

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.

回答

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>协议一致性限制为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 *' 

注意。默认情况下,您将收到对象类型不匹配的警告,如果您想要接收错误,您可以启用Treat all warnings as errors构建设置,或者仅启用Treat Incompatible Pointer Type Warnings as Errors

相关问题