OC是一门动态类型语言

说动态类型之前,先说俩概念:编译、运行。


编译:编译简单来讲就是把自己写的源代码翻译成机器能识别的语言。可以认为是编译器检查语法、识别静态类型数据等过程,是不会将代码运行到内存中去的,也就是说编译时是没有内存分配的


运行:就是将代码加载到内存中去,并在内存中做一些操作和判断等。


OC的动态特性体现在三个方面:

动态类型、动态绑定、动态加载

1.1 动态类型

     简单来讲,动态类型就是id类型,它区别于静态类型(如int类型、NSString等基本类型,在编译阶段会被识别,静态类型可以提高程序的可读性),这些id类型只有在运行的时候(runtime)才会根据语境来识别,编译时不会被识别。

比如:一个id类型的对象,若我们不确定其类型,则通常会用 isKindOfClass方法去判断,然后对响应处理

// 不确定obj类型
id obj = name;   
// 做判断,若obj为NSString类型
if ([obj isKindOfClass:[NSString class]]) {
// 做相应处理
NSString * str = (NSString *)name;
}

上面的isKindOfClass就是通常用的一种动态类型识别的一个函数,其他还有诸如

-(BOOL)isMemberOfClass:classObj是否是classObj的实例

-(BOOL)respondsTosSelector:selector  类中是否有这个方法

NSClassFromString(NSString*);由字符串得到类对象

NSStringFromClass([类名 Class]);由类名得到字符串

Class rectClass= [Rectangle class];通过类名得到类对象

Class aClass =[anObject class];通过实例得到类对象

if([obj1 class]== [obj2 class])判断是不是相同类的实例

等常见动态类型识别方法

补充:

类对象

*类对象再程序运行时一直存在。

*类对象是一种数据结构,存储类的基本信息:类大小,类名称,类的版本以及消息与函数的映射表等

*类对象所保存的信息在程序编译时确定,在程序启动时加载到内存中。

*类对象代表类,class代表类对象,类方法属于类对象

*如果消息的接收者是类名,则类名代表类对象

*运行时,所有类的实例都由类对象生成,类对象会把实例的isa的值修改成自己的地址,每个实例的isa都指向该实例的类对象

*从类对象里可以知道父类信息、可以响应的方法等

*类对象只能使用类方法,不能用实例方法


任意NSObject的子类都会继承NSObject的isa实例变量,isa是一个指针,当NSObject的子类实例化对象时,isa 实例变量永远是对象的第一个实例变量。运行时,所有类的实例对象都由类对象产生,类对象会把实例对象的 isa 指针修改成自己的地址,每个实例对象的 isa 指针都指向该实例的类对象,从类对象中可以获取父类信息,可响应的方法等


多态:不同的对象以自己的方式响应相同的消息。


1.2动态绑定

     一个对象何时调用指定的方法不是在编译时决定,而是在运行时决定的。

    OC中,对象调用函数称为消息发送。[obj  msgSend];  obj为消息的接受者,msgSend为消息名

消息函数的作用如下:

*首先动态确定消息接受者 (obj) 的类型,找到接受者的 isa 指针,然后在 isa 指针指向的 Class 对象中使用第二个参数 selector 查找方法;

*如果没找到,就使用当前class中的新的 isa 指针到上一级父类对象中查找

*找到方法后,再根据obj中的 self 指针找到当前的对象,调用当前对象的具体实现的方法(IMP)。然后传参,调用实现方法

*若一直找到NSObject的class对象仍未找到所调用的方法,就会报不能识别发送消息的错误

   Unrecognized selector send to instance xxx...



1.3动态加载

举个例子,开发的时候icon图片的时候在Retina设备上要多添加一个张@2x的图片,当设备更换的时候,图片也会自动的替换。

再有就是例如运行时加载新类,以及方法的动态加载等,这两个我尚未深入研究,有时间再细看。