NSObject*、id和instancetype

89 阅读3分钟

动态、静态类型

动态类型

动态类型指的是对象指针类型的动态性,具体是指使用id修饰后将对象的类型确定推迟到运行时,由赋给它的对象类型决定对象指针的类型。也就是说id修饰的对象为动态类型对象,其他在编译器指明类型的为静态类型对象,通常如果不需要涉及到多态的话还是要尽量使用静态类型(原因:错误可以在编译器提前查出,可读性好)。

// 动态类型
id obj = [[TestObject alloc] init];

静态类型

一个指针变量指向特定类的对象时,使用的是静态类型,在编译的时候就知道这个指针变量所属的类。使用静态类型时,编译器在编译期间,会做许多的类型检查:因为编译器需要知道哪个对象该如何使用。

// 静态类型
TestObject obj = [[TestObject alloc] init];

苹果官方objc.h文件里有关于id的定义:

/// A pointer to an instance of a class.
typedef struct objc_object *id;
  • id可以用于指向所有的Objective-C对象,是一种万能指针,类似于C语言中的void *

  • id类似NSObject *可以指向所有继承自NSObject的对象,因为在Objective-C中NSObject是基类,绝大多数的类继承自NSObject,因此根据面向对象编程的多态特性,NSObject *可以指向Objective-C中绝大多数的类的实例对象。

使用id修饰的对象是动态类型,编译器在编译期不会去判断其真实类型,因此id指向的对象不管向其发送任何消息,编译器在编译期都不会有任何报错

使用NSObject *修饰的对象是静态类型,在编译期就已经明确该对象是NSObject对象,因此当我们对该对象发送NSObject没有声明的方法时,编译器就会果断报错

关联、非关联类型

关联返回类型

根据Cocoa的命名规则,满足下述规则的方法:
1. 类方法中,以allocnew开头
2. 实例方法中,以autoreleaseinitretainself开头
当方法返回值为id类型时,编译器不会返回一个类型不明的对象,会返回一个方法所在类类型的对象,这些方法就被称为是关联返回类型的方法。换句话说,这些方法的返回结果以方法所在的类为类型。

非关联返回类型

与关联返回类型相反
1. 类方法中,不以allocnew开头
2. 实例方法中,不以autoreleaseinitretainself开头
当方法返回值为id类型时,编译器会返回一个类型不明的对象,即id类型的对象。

instancetype其实就是为了扩大关联返回类型的范围,让不是以上述关键字开头的方法的返回值也是关联返回类型。

总结一下区别与联系:

  • idinstancetype都可以做方法的返回值。
  • id类型的返回值在编译期不能判断对象的真实类型,即非关联返回类型,instancetype类型的返回值在编译期可以判断对象的真实类型,即关联返回类型。
  • id可以用来定义变量, 可以作为返回值, 可以作为形参,instancetype只能用于作为返回值。