本节书摘来自华章出版社《编写高质量代码:改善objective-c程序的61个建议》一 书中的第1章,第1.5节,作者:刘一道,更多章节内容可以访问云栖社区“华章计算机”公众号查看。
实例类型(instancetype)是objective-c语言中新添加的一个返回类型,实例类型作为方法返回的实例的类型,是苹果在2013年的年度大会上宣布的。这个新添加的实例类型不仅可用来作为objective-c方法的返回类型,且能用这个实例类型来作为向编译器的提示,提示方法返回的类型将是方法所属的类的实例。
类的实例,作为方法返回类型,宜采用关键字instancetype作为方法的返回类型,如alloc 、init和类工厂方法等。使用instancetype作为类(或者类的子类)的实例返回类型,可以大大改善objective-c代码的类型安全。例如,考虑下面的代码:
通过上面的代码可以看到,instancetype作为+ factorymethoda的返回类型,也就是说,该消息的类型表达式是myobject *。但是myobject由于先天缺乏一个-count方法,编译器将会对此给出一个关于x行的警告:
对于这样的情况,如果把instancetype换成id作为实例的方法返回类型,也就是如上面的代码中的实例,id作为类方法 + factorymethodb的返回类型。在编译器编译的过程中不会发出关于y行的警告。
为什么编译器没有给出警告?因为 id类型的对象可以作为任何类,并且调用的方法-count在一些类中存在,故此向编译器发出方法+factorymethodb返回值实现了-count的信息,从而编译器没有给出警告。对于该种编写代码的方法,在无形中埋下了隐患。
为了确保instancetype工厂方法有正确的子类的行为,一定要使用[self class]分配类,而不是直接引用类名。遵循这个惯例,记住,务必要使编译器能正确地推断出子类类型。例如,依据前面的示例,考虑尝试做一个前面myobject子类示例:
对于上述代码,编译器将会给出警告,如下面的警告:
在该示例中,+factorymethoda消息发送之后,将返回一个类型myobjectsubclass的对象实例。编译器就能恰当地确定 + factorymethoda的返回类型应该是子类myobjectsubclass,而不是工厂方法中所声明的超类。
在编写代码中,通常在处理init 方法和类工厂方法时,宜用instancetype类替换 id作为返回值。在新版本xcode 5中,虽然,编译器会自动地把alloc、init、new方法之中的id转化为instancetype类型,但对于这几种方法之外的其他方法,编译器则不会进行转化。在objective-c的公约之中,明确地建议对于所有方法尽可能用instancetype而非id。也就是说,作为返回值,id由于其自身的缺陷,在objective-c中会逐渐退出,由instancetype来替代。
仅有在作为返回值时,宜用instancetype来替换id,而不是代替代码中所有id。与id不同,instancetype关键字仅能作为方法声明的返回类型。也就说,在某一个特定区域,instancetype可以替代id,并非所有区域都可以替代id。
例如:
要点
(1)instancetype仅仅用来作为objective-c方法的返回类型。
(2)使用instancetype可避免隐式转换id而造成的欺骗性编译无误通过的现象,防止程序正式运行时出现崩溃现象,可以大大改善objective-c代码的类型安全。
(3)在某一个特定区域,instancetype可以替代id,并非所有区域都可以替代id。