2016-01-21 33 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

相關問題