为什么使用instancetype?

时间:2016-03-15 19:35:56

标签: ios objective-c instancetype

有人可以向我解释(简单来说)为什么在Objective-C中使用instancetype

- (instancetype) init { 
    self = [super init];
    if (self) { 
        // Custom initialization
    } 
    return self; 
} 

3 个答案:

答案 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