如果一个方法将返回本类的一个实例对象, 那么推荐使用instancetype关键字来作为它的返回类型. 这些方法包括alloc, init以及类的工厂方法.
在合适的地方, 用instancetype代替id可以提高Objective-C代码的类型安全性. 举个例子, 考虑下面的代码:
@interface MyObject : NSObject
+ (instancetype)factoryMethodA;
+ (id)factoryMethodB;
@end
@implementation MyObject
+ (instancetype)factoryMethodA {
return [[[self class] alloc] init];
}
+ (id)factoryMethodB {
return [[[self class] alloc] init];
}
@end
- (void)doSomething {
NSUInteger x, y;
x = [[MyObject factoryMethodA] count]; // 报错
y = [[MyObject factoryMethodB] count]; // 不报错
}
因为+factoryMethodA的返回值类型为instancetype, 所以[MyObject factoryMethodA]返回一个MyObject类的对象. 而MyObject类并没有定义-count方法, 所以编译器在x那一行会报错, 有助于我们在开发阶段就发现错误并且进行修正.
然而, +factoryMethodB的返回值类型为id, 编译器就不能给出任何警告或者错误信息, 因为id修饰的对象可能是任意类的实例, -count方法可能就存在于某个类中.
为了确保instancetype工厂方法在子类中也能有正确的行为, 一定要用[self class]来给对象分配空间, 而不要直接使用类名, 这可以确保编译器能正确推断出子类的类型. 举个例子, 定义一个MyObject的子类:
@interface MyObjectSubclass : MyObject
@end
@implementation MyObjectSubclass
@end
- (void)doSomething {
NSString *aString = [MyObjectSubclass factoryMethodA]; // 报警告, 类型不匹配
}
在例子中, 编译器可正确推断出[MyObjectSubclass factoryMethodA]返回一个MyObjectSubclass类的对象, 而不是父类MyObject.
注意, 只有作为返回类型时, instancetype才可替换id, 而不是所有的情况, 和id不同, instancetype关键字只能作为返回类型.