Objective c 在目标C中,为什么允许我在没有错误或警告的情况下将NSArray分配给NSMutableArray?
我被一种奇怪的行为所困扰,如下例所示:Objective c 在目标C中,为什么允许我在没有错误或警告的情况下将NSArray分配给NSMutableArray?,objective-c,cocoa,clang,Objective C,Cocoa,Clang,我被一种奇怪的行为所困扰,如下例所示: NSMutableArray *a1 = [[NSMutableArray alloc] init]; // fine NSMutableArray *a2 = [NSMutableArray array]; // fine, too // compiler reports incompatible pointer types; good: NSMutableArray *a3 = [[NSArray alloc] init]; //
NSMutableArray *a1 = [[NSMutableArray alloc] init]; // fine
NSMutableArray *a2 = [NSMutableArray array]; // fine, too
// compiler reports incompatible pointer types; good:
NSMutableArray *a3 = [[NSArray alloc] init];
// compiler says nothing and is happy to assign this!
NSMutableArray *a4 = [NSArray array];
NSArray
和NSMutableArray
类的init
和array
方法都返回id
。然而,我调用这些方法时的行为完全不同,而clang让我很高兴地将一个空的NSArray
分配给NSMutableArray
变量
结果是,并因此能够在编译时确定[[NSArray alloc]init]
返回NSArray*
而不是NSMutableArray*
。但是这个检查根本不适用于array
方法
为什么??像我上一个例子那样的行不应该至少产生一个警告吗?为什么所有这些方法都不声明为返回instancetype
?将来会改变吗
更新
好消息:从iOS 7开始,
[NSArray array]
返回instancetype
,因此上面对a4
的赋值也会产生警告。其他方法,如arrayWithContentsOfFile:
或arrayWithContentsOfURL
仍然返回id
,尽管…事实证明,您不仅可以使用错误的数组类型,还可以使用带有返回id
的方便初始值设定项的任何对象的错误类型。例如,编译时不会出现警告:
NSMutableArray *a4 = [NSDictionary dictionary];
这是使用id
选择退出类型安全性的一个副作用,正如您所注意到的,它应该是不推荐的行为,并替换为instancetype(以上述方式使用时会引发不兼容的类型警告)
不幸的是,这不是一个buginstancetype
作为一个全新的关键词,它的应用还没有普及,在苹果的整个框架中开始使用它将是一个大胆的举动。你永远不会知道,下一个SDK总是有希望的
但是这个检查对于数组方法根本不起作用。为什么?
正如您链接的文档所描述的,这是因为-array
不会生成可识别的相关结果类型。ObjC是非常动态的——编译器不能保证+数组的结果类型。由于命名约定定义良好(例如,+alloc
,-init
,+new
,-self
,等等),因此在某些方法中确实做出了这种假设。因此,这个实现只是诉诸命名约定
编译器还会在您可能不期望的区域验证某些命名约定:
@implementation NSArray (DEMO)
- (id)initStr
{
return [NSString new]; // << warning. RE: init prefix
}
@end
@实现NSArray(演示)
-(id)initStr
{
返回[NSString new];//我会在上提交一个bug,并在这里提到bug编号。@ericgorr问题是,它不是bug。@Jean Philippellet:很抱歉,我复制了你的问题…@AnoopVaidya我想你误解了id
的用途。bug报告rdar://13357852Thanks. 我一直想知道为什么这些方法在第一个p中应该返回id
lace而不是返回的实际类型。为什么要像这样丢弃类型安全性?这样它们就不会破坏子类。如果在初始值设定项中放弃类型安全性,那么子类S可以重写t的init方法并返回自己,而不带类型检查警告。如果ObjC像java一样,初始值设定项是唯一的,默认情况下不会继承,则不是问题。嗯,我发现不返回id
实际上不是问题,因为clang允许您在重写的方法中返回协变子类型。所以子类也应该可以。