Objective-C语言的动态性主要体现在以下3个方面
(1)动态类型:运行时确定对象的类型。
(2)动态绑定:运行时确定对象的方法。
(3)动态加载:运行时加载需要的资源或者或代码模块。
一、动态类型
动态类型指对象指针类型的动态性,具体地说就是使用id类型将对象的类型推迟到运行时才确定,由赋给它的对象类型决定该对象类型(说起来怎么这么绕口),也就是说id修饰的对象是动态类型对象,其他在编译期指明类型的为静态类型对象,所以开发中如果不是涉及到多态,尽量还是使用静态的类型,这样编写错误,编译器会提前查出问题,可读性更高一点。
//编译时认为是NSString,这是赋值了一个NSData对象编译器会给出警告信息:Incompatible pointer types initializing 'NSString *' with an expression of type 'NSData *'
NSString *testObject = [[NSData alloc]init];
//编译其认为是NSString,所以允许使用NSString的方法,不会有警告和错误,
[testObject stringByAppendingString:@"string"];
//编译期不允许使用NSData的方法,错误提示;No visible @interface for 'NSString' declares the selector 'base64EncodedDataWithOptions:'
[testObject base64EncodedDataWithOptions:NSDataBase64Encoding64CharacterLineLength];
如以上代码,testObject在编译时,指针的类型是NSString,也就是说编译时期是被当做一个NSString类型来处理,编译器在类型检查时发现类型不匹配会给出警告信息,testObject在运行时,指针指向的是一个NSData对象,因此如果指针调用了NSString的方法,那么虽然编译通过了,但运行时会出现崩溃,
二、动态绑定
动态绑定是建立在动态类型的基础之上,在OC的消息分发机制下将要执行的方法推迟到运行时才确定,可以动态的添加方法。也就是说一个OC对象是否调用某个方法不是在编译器确定的,方法的调用不和代码绑定在一起,而是到了运行时根据发出的具体消息,才去动态的确定需要调用的代码。
三、动态加载
动态加载分为两部分:动态资源的加载(如:图片资源),代码模块的加载;这些都是在运行时根据需要有选择性的添加到程序中的,是一种代码和资源的“懒加载”模式,这样降低编译时期对内存的开销,提供程序的性能。
如:资源在动态加载图片进行屏幕适配时,因为同一个图片对象可能会准备几种不同分辨率的图片资源,程序就会根据当前机型动态的选择对应分辨率的图片,如:@1x,@2x,@3x的。
四、消息传递机制
在OC中,方法的调用不能再去理解为对象调用其方法,而是要理解成对象接收消息。消息的发送采用“动态绑定”的机制,具体会调用那个方法直到运行时才确定。方法的调用其实就是告诉对象要做些什么事,给对象发送一个消息,对象为就是接收者recevier,调用的方法及其参数就是消息message,如果要给一个对象传递消息,可以表示为:[receiver message:xxx]。
在消息传递机制中,当开发者编写[receiver message:xxx]语句进行发送消息后,编译器都会将其转换成objc_msgSend C语言的发送格式。格式为:
void objc_msgSend(id self, SEL sel ...);
这个函数参数可变,第一个参数填入消息的接收者,第二个参数传入的是消息,后面可以跟一下可选的消息参数。有了这些参数,objc_msgSend就能根据接收者的isa指针,到其对象的方法列表中以sel 的名称寻找对应的方法。若找到对应的方法,就会转到它的实现代码执行,如果找不到,就去父类中寻找,如果找到了根类还是无法找到对应的方法,说明接收者对象无法响应该消息,那么就会触发消息转发机制,给开发者一次补救程序的机会。
五、消息转发机制
如果在消息传递过程中,接收者无法响应收到的消息,那么就会触发到消息转发机制。
消息转发提供了3道防线,任何一个起了作用,都能补救此次消息转发。依次为:
(1)动态的补加方法的实现
+(BOOL)resolveClassMethod:(SEL)sel
+(BOOL)resolveInstanceMethod:(SEL)
(2)直接返回消息到转发到的对象(就是将消息发送到另一个对象去处理)
-(id)forwardingTargetForSelector:(SEL)aSelector
(3)手动生成签名并转发给另外一个对象
-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
-(void)forwardInvocation:(NSInvocation *)anInvocation
六、OC的编译时和运行时都做了哪些工作?
编译时:该阶段,编译器对语言进行编译,编译器只会对语言进行最基本的检查报错、语法分析等,并将程序代码翻译成计算机能够识别的语言。那编译通过了,是不是就可以成功执行呢?你太单纯了,想的美。
运行时:程序通过了编译之后,就会将编译好的代码转载到内存中,这时候就会对类型进行检查,不仅仅是简单的扫描分析,此时若出现问题,程序可就Game Over了。
编译时就是一个静态的阶段,类型明显错误,就会被直接检查出来,运行时时动态的阶段,会将程序与开发环境结合起来。
OC是动态运行时语言,主要指的是OC语言的动态性。
动态性即OC的动态类型、动态绑定、动态加载,将对象类型的确定、方法调用的确定、代码和资源的转载推迟到运行时记性,灵活方便。
Runtime的相关内容之前在一篇博客中已经写过:https://www.cnblogs.com/xjf125/p/10154488.html