Objective-C 中 id 和 instancetype 的使用与异同
今天记录一下在Objective-C中,保留字id和instancetype各自的用法,以及异同。
id
什么是id类型
在概念上,id类似于Java中的Object类,可以转换为任何数据类型。换句话说,id类型的变量可以存放任何数据类型的对象。在内部处理上,这种类型被定义为指向对象的指针,实际上是一个指向这种对象的实例变量的指针。
下面是id类型在Objective-C中的定义:
typedef struct objc_object {
Class isa;
} *id;
从上面看出,id是指向struct objc_object的一个指针。也就是说,id是一个指向任何一个继承了Object(或者NSObject)类的对象。
id的用法
id是一个指针
因为id类型是一个指针,所以我们在使用id类型的时候不需要添加任何的星号,例如:
id foo = nil;
上面的代码声明了一个id类型的指针foo,这个指针指向NSObject的任意一个子类。
而下面的代码则定义了一个指针,这个指针指向另一个指针,被指向的这个指针指向NSObject的一个子类。
id *foo = nil;
可以接收任何消息
在ObjeciveC中,id是可以接收任何消息的,所以我们可以将一个方法或者一个变量声明为id类型,用来接收多种类型的数据。
例如NSArray中即可以接收NSString,也可以是NSObject,这时候就需要用id了。
小结
在我的理解看来,id类型就是一个万能的类型,当我们暂时不知道方法的返回值该是什么类型的时候,我们可以先尝试将方法定义为id类型,等待确定方法返回值后再回来修改,或者就直接定义为id类型罢了。
或者我们可以定义一个id类型的变量,用它来做中间变量,用来接收多种类型的数据。
关联返回类型
在介绍instancetype之前先讲解一个概念,就是关联返回类型的方法。
根据Cocoa的命名规则,满足下述规则的方法:
- 类方法中,以
alloc或new开头 - 实例方法中,以
autorelease,init,retain或self开头
会返回一个方法所在类 类型 的变量,这里我用空格和加粗断句,方便大家理解。也就是说,这些方法的返回值的类型,是调用这些方法的那个类的类型。NSArray调用的alloc方法,即[NSArray alloc]。那么这个方法的返回值就是NSArray类型的。同理[[NSArray alloc] init]返回的也是NSArray类型的值。
那么说回来,以上这些的方法呢,我们就称之为关联返回类型的方法。
instancetype
什么是instancetype类型
instancetype是从 clang 3.5 开始提供的一个关键字,表示某个方法返回的未知类型的Objective-C对象。单看这个定义,感觉和id还是挺像的。
instancetype的作用
当我们有一个自定义的方法,例如下面这个:
@interface UIView (TestView)
+ (id) testFounation;
@end
TestView类是UIView类的分类,当我们如下调用testFounation方法时
[TestView testFounation];
其返回值的类型和方法的声明相同,是id类型。
而如果我们如下使用instancetype声明testFounation的话
@interface UIView (TestView)
+ (instancetype) testFounation;
@end
当我们再次调用testFounation方法:
[TestView testFounation];
其返回值的类型会是TestView类型。
小结
综上我们可以看出,instancetype的作用实际上就是使非关联返回类型的方法返回所在类的类型。
通俗的讲,就是当我们需要方法的返回类型不是未知的id类型,而是具体的,调用该方法的类的类型的时候,我们要使用instancetype类型。
再具体一些,当我们自定义init方法的时候,其返回值就是instancetype类型。
id和instancetype的异同
总结下来,id和instancetype的异同一共有以下几点:
相同之处
其都可以作为方法的返回类型。
不同之处
instancetype可以返回和方法所在类相同类型的对象,id只能返回未知类型的对象。instancetype只能作为返回值,不能像id那样作为参数。instancetype只适用于初始化方法和便利构造器的返回值类型。- 在不同的内存管理机制中:
- 在ARC(Auto Reference Count)环境下:
instancetype用来在编译期确定实例的类型,而使用id的话,编译器不检查类型, 运行时检查类型。 - 在MRC(Manual Reference Count)环境下:
instancetype和id一样,不做具体类型检查。
- 在ARC(Auto Reference Count)环境下:
关于第三点,因为我现在还没有具体学习到内存管理相关的知识,可以参考下方参考中三木成森的文章,有举例说明该点。