有人可以向我解释(简单来说)为什么在Objective-C中使用instancetype
?
- (instancetype) init {
self = [super init];
if (self) {
// Custom initialization
}
return self;
}
答案 0 :(得分:16)
回到过去,初始化者只返回了http://example.com/baz/boo.php
类型的对象(任何对象)。
使用普通的初始化程序(以“init”,“alloc”或“new”开头的那些),这通常不是问题。编译器会自动推断它返回的类型,因此将对象的任何方法调用都限制为该类的实例方法。
但是, 是静态便利初始化程序或“工厂方法”的问题,它们不一定遵循相同的命名约定 - 因此它无法应用相同的类型安全性。
这意味着使用这样的类:
id
编译器会接受这样的代码:
@interface Foo : NSObject
+(id) aConvenienceInit;
@end
为什么呢?因为返回的对象可能是任何对象,所以如果您尝试访问NSArray* subviews = [Foo aConvenienceInit].subviews;
属性 - 没有类型安全可以阻止您。
但是,现在使用UIView
,您获得的结果是您给定实例的类型。现在使用此代码:
instancetype
您将收到编译器警告,指出属性@interface Foo : NSObject
+(instancetype) aConvenienceInit;
@end
...
NSArray* subviews = [Foo aConvenienceInit].subviews;
不是subviews
的成员:
虽然值得注意的是,如果您的方法以“alloc”,“init”或“new”开头,编译器会自动将返回类型从Foo*
转换为id
- 但仍使用{{ 1}}无论你身在何处都是一个很好的习惯。
有关详细信息,请参阅instancetype
上的Apple docs。
答案 1 :(得分:11)
想象一下两个类:
@interface A : NSObject
- (instancetype)init;
@end
@interface B : A
@end
init
中的A
方法会继承到B
。但是,在这两个类中,该方法具有不同的返回类型。在A
中,返回类型为A
,而B
的返回类型为B
。
没有其他方法可以正确声明初始值设定项的返回类型。请注意,大多数带有类的编程语言甚至都没有构造函数的返回类型,因此它们完全避免了这个问题。
这就是为什么Obj-C 需要 instancetype
,但当然它也可以在初始化器之外使用。
答案 2 :(得分:0)
如果您还在Swift中使用此代码,那么在Objective-C中使用instancetype
而不是id
很重要。考虑以下类声明:
@interface MyObject : NSObject
+ (id)createMyObject;
- (void)f;
@end
如果要在Swift 5.3中使用MyObject
创建一个createMyObject
实例,然后为此对象调用f
,则必须执行以下操作:
let a = MyObject.createMyObject()
(a as? MyObject)?.f()
现在将id
中的instancetype
替换为MyObject
,以得到以下Swift代码:
let a = MyObject.create()
a?.f()
现在您可以看到,可以使用MyObject.create()
代替MyObject.createMyObject()
。而且您无需使用(a as? MyObject)
,因为a
被定义为MyObject?
而不是Any
。