Objc id - deepindo/DoNote GitHub Wiki

1. 静态类型和动态类型

静态类型:

将一个指针变量定义为特定类的对象时,使用的是静态类型,在编译的时候就知道这个是指针变量所属的类,这个变量总是存储特定类的对象;

Person *p = [Person new];

动态类型:

这一特性是程序直到执行时才确定对象所属的类;

2. 为什么要有动态类型

我们知道NSObject是OC中的基类,那么任何对象的NSObject类型的指针可以指向任意对象,都没有问题,但是NSObject是静态类型,如果通过它直接调用NSObject上不存在的方法,编译器会报错,如果想通过NSObject的指针调用特定对象的方法,就必须把NSObject *这种类型强转成特定类型,然后调用,如下:

/// 定义NSObject *类型
NSObject *obj = [Cat new];
Cat *c = (Cat *)obj;
[c eat];

id是一种通用的对象类型,它可以指向属于任何类的对象,也可以理解为万能指针,相当于C语言的void *, 因为id是动态类型,所以可以通过id类型直接调用指向对象中的就去,编译器不会报错, 如下objc.h文件中对于objc_object结构体以及id的定义,可以看出id是objc_object结构体指针。

/// Represents an instance of a class.
struct objc_object {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;
};

/// A pointer to an instance of a class.
typedef struct objc_object *id;

在id的定义中,已经包好了*号,id指针只能指向OC中的对象,为了尽可能的减少编程中出错,xcode做了一个检查,当使用id类型的调用本项目中所有类中都没有的方法,编译器会报错,id类型不能使用点语法,因为语法是编译时特性,而id是运行时特性

3. id数据类型与静态类型

虽说id数据类型可以存储任何类型的对象,但是不要养成滥用这种通用类型,如没有使用到多态尽量使用静态类型,静态类型可以更早的发现错误,在编译阶段而不是运行阶段,静态类型能够提高代码的可读性,使用动态类型前最好判断其真实类型