为什么通用NSDictionary不会提示有关错误键入的键/赋值?
问题描述:
为什么以下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'
为什么字面赋值或不正确类型的键会导致警告/错误?
答
看来这是编译器的限制/错误,造成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
。