为什么以下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'
为什么不进行字面分配或键入不正确的密钥会导致警告/错误?
答案 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}}一个。