1.相关术语

  • 动态语言(动态编程语言):是一类在运行时可以改变其结构的语言:例如新的函数、对象、甚至代码可以被引进,已有的函数可以被删除或是其他结构上的变化。通俗点说就是在运行时代码可以根据某些条件改变自身结构。主要动态语言:Objective-C、C#、JavaScript、PHP、Python、Erlang。
  • 静态语言(静态编程语言):与动态语言相对应的,运行时结构不可变的语言就是静态语言。如Java、C、C++。
  • 动态类型语言:动态类型语言是指在运行期间才去做数据类型检查的语言。动态类型语言的数据类型不是在编译阶段决定的,而是把类型绑定延后到了运行阶段。主要语言:Python、Ruby、Erlang、JavaScript、swift、PHP、Perl。
  • 静态类型语言:静态语言的数据类型是在编译其间确定的或者说运行之前确定的,编写代码的时候要明确确定变量的数据类型。主要语言:C、C++、C#、Java、Objective-C。

⚠️注意:动态类型语言和动态语言是完全不同的两个概念。前者关注数据类型,而后者关注代码结构。

2.为什么说OC是动态运行时语言

首先,OC 是动态语言,因为 OC 通过可以通过动态绑定改变自身结构。其次 OC 将数据类型的确定由编译时,推迟到了运行时。

关于类型检查,一般会把类型分为两类:动态的和静态的,分别对应动态类型语言和静态类型语言。

  • 动态类型:动态的在运行时做检查。以往,编写代码时可以向任意对象发送任何消息,在运行时,才会检查对象是否能够响应这些消息。由于只是在运行时做此类检查,所以叫做动态类型。
  • 静态类型:静态类型在编译时做检查。当在代码中使用 ARC 时,编译器在编译期间,会做许多的类型检查:因为编译器需要知道哪个对象该如何使用。例如,如果 myObject 没有 hello 方法,那么就不能写如下这行代码了。

  • [myObject hello];

⚠️注意:从以上可以看出 OC 是动态语言,也是静态类型语言,但是 OC 中类型、对象属性和方法的真正确定是在运行时(动态类型),所以 OC 是动态运行时语言。

以下介绍 OC 的动态性。

OC 语言的动态性主要体现在三个方面:动态类型(Dynamic typing)、动态绑定(Dynamic binding)和动态加载(Dynamic loading)。

2.1 动态类型

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

示例:

对于语句NSString *testObject = [[NSData alloc] init]; testObject 在编译时和运行时分别是什么类型的对象?

首先 testObject 是一个指向某个对象的指针,不论何时指针的空间大小是固定的。

编译时: 指针的类型为 NSString,即编译时会被当成一个 NSString 实例来处理,编译器在类型检查的时候如果发现类型不匹配则会给出黄色警告,该语句给指针赋值用的是一个 NSData 对象,则编译时编译器则会给出类型不匹配警告。但编译时如果 testObject 调用 NSString 的方法编译器会认为是正确的,既不会警告也不会报错。

运行时: 运行时指针指向的实际是一个 NSData 对象,因此如果指针调用了 NSString 的方法,虽然编译时通过了,但运行时会崩溃,因为 NSData 对象没有该方法;另外,虽然运行时指针实际指向的是 NSData,但编译时编译器并不知道(前面说了编译器会把指针当成 NSString 对象处理),因此如果试图用这个指针调用 NSData 的方法会直接编译不通过,给出红色报错,程序也运行不起来。

下面给出测试例子:

// 1.编译时编译器认为 testObject 是一个 NSString 对象,这里赋给它一个 NSData 对象编译器给出黄色类型错误警告,但运行时却是指向一个 NSData 对象
NSString *testObject = [[NSData alloc] init];// 2.编译器认为 testObject 是 NSString 对象,所以允许其调用 NSString 的方法,这里编译通过无警告和错误
[testObject stringByAppendingString:@"string"];// 3.但不允许其调用 NSData 的方法,下面这里编译不通过给出红色报错
[testObject base64EncodedDataWithOptions:NSDataBase64Encoding64CharacterLineLength];

将上面第三句编译不通过的注释掉,然后在第二句打断点,编译后让程序跑起来到断点出会看到 testObject 指针的类型是 _NSZeroData,指向一个 NSData 对象。继续运行程序会崩溃,因为 NSData 对象没有 NSString 的 stringByAppendingString 这个方法。

那么,假设 testObject 是 id 类型会怎样呢?

// 1.id 任意类型,编译器就不会把 testObject 再当成 NSString 对象了
id testObject = [[NSData alloc] init];// 2.调用 NSData 的方法编译通过
[testObject base64EncodedDataWithOptions:NSDataBase64Encoding64CharacterLineLength];// 3.调用 NSString 的方法编译也通过
[testObject stringByAppendingString:@"string"];

结果是编译完全通过,编译时编译器把 testObject 指针当成任意类型,运行时才确定 testObject 为 NSData 对象(断点看指针的类型和上面的例子中结果一样还是 _NSZeroData,指向一个 NSData 对象),因此执行 NSData 的函数正常,但执行 NSString 的方法时还是崩溃了。通过这个例子也可以很清楚的知道 id 类型的作用了,将类型的确定延迟到了运行时。

动态类型识别方法

  • 首先是Class类型

    • Class class = [NSObject class]; // 通过类名得到对应的 Class 动态类型
    • Class class = [obj class]; // 通过实例对象得到对应的 Class 动态类型
    • if([obj1 class] == [obj2 class]) // 判断是不是相同类型的实例
  • Class动态类型和类名字符串的相互转换

    • NSClassFromString(@”NSObject”); // 由类名字符串得到 Class 动态类型
    • NSStringFromClass([NSObject class]); // 由类名的动态类型得到类名字符串
    • NSStringFromClass([obj class]); // 由对象的动态类型得到类名字符串
  • 判断对象是否属于某种动态类型

    • - (BOOL)isKindOfClass:Class // 判断某个对象是否是动态类型 Class 的实例或其子类的实例
    • - (BOOL)isMemberOfClass:Class // 与 isKindOfClass 不同的是,这里只判断某个对象是否是 Class 类型的实例,不放宽到其子类
  • 判断类中是否有对应的方法

    • - (BOOL)respondsTosSelector:(SEL)selector // 类中是否有这个类方法
    • - (BOOL)instancesRespondToSelector:(SEL)selector // 类中是否有这个实例方法

    注意:上面两个方法都可以通过类名调用,前者判断类中是否有对应的类方法(通过‘+’修饰定义的方法),后者判断类中是否有对应的实例方法(通过‘-’修饰定义的方法)。此外,前者 respondsTosSelector 函数还可以被类的实例对象调用,效果等同于直接用类名调用后者 instancesRespondToSelector 函数。

    举个例子:假设有一个类 Test,有它的一个实例对象 test,Test 类中定义了一个类函数:+ (void)classFun;和一个实例函数:- (void)objFunc;,那么各种调用情况的结果如下:

    [1][Test respondsToSelector:@selector(objFunc)];//NO
    [2][Test respondsToSelector:@selector(classFunc)];//YES[3][Test instancesRespondToSelector:@selector(objFunc)];//YES
    [4][Test instancesRespondToSelector:@selector(classFunc)];//NO[5][test respondsToSelector:@selector(objFunc)];//YES
    [6][test respondsToSelector:@selector(classFunc)];//NO

    结论: 如果想判断一个类中是否有某个类方法,应该使用 [2] ; 如果想判断一个类中是否有某个实例方法,可以使用 [3] 或者 [5] 。

  • 方法名字符串和SEL类型的转换

    在编译器,编译器会根据方法的名字和参数序列生成唯一标识改方法的 ID,这个 ID 为 SEL 类型。到了运行时编译器通过 SEL 类型的 ID 来查找对应的方法,方法的名字和参数序列相同,那么它们的 ID 就都是相同的。另外,可以通过 @selector() 指示符获得方法的 ID。常用的方法如下:

    SEL funcID = @selector(func);// 这个注册事件回调时常用,将方法转成 SEL 类型SEL funcID = NSSelectorFromString(@"func"); // 根据方法名得到方法标识NSString *funcName = NSStringFromSelector(funcID); // 根据 SEL 类型得到方法名字符串

2.2 动态绑定

基于动态类型,在某个实例对象被确定后,其类型便被确定了。该对象对应的属性和响应的消息也被完全确定,这就是动态绑定。在继续之前,需要明确 Objective-C 中消息的概念。由于 OC 的动态特性,在 OC 中其实很少提及“函数”的概念,传统的函数一般在编译时就已经把参数信息和函数实现打包到编译后的源码中了,而在 OC 中最常使用的是消息机制。调用一个实例的方法,所做的是向该实例的指针发送消息,实例在收到消息后,从自身的实现中寻找响应这条消息的方法。

动态绑定所做的,即是在实例所属类确定后,在运行时动态的为类添加属性和方法,以及方法的最后处理或转发,这里所指的属性和方法当然包括了原来没有在类中实现的,而是在运行时才需要的新加入的实现。

属性的处理主要涉及如下两个方法:

//setter
OBJC_EXPORT void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy);//getter
OBJC_EXPORT id objc_getAssociatedObject(id object, const void *key);

方法的处理请参考这里——iOS开发笔记(三):消息传递与转发机制

2.3 动态加载

动态加载主要包括两个方面,一个是动态资源加载,一个是一些可执行代码模块的加载,这些资源在运行时根据需要动态的选择性的加入到程序中,是一种代码和资源的“懒加载”模式,可以降低内存需求,提高整个程序的性能,另外也大大提高了可扩展性。

  • 动态资源加载:例如,资源动态加载中的图片资源的屏幕适配,同一个图片对象可能需要准备几种不同分辨率的图片资源,程序会根据当前的机型动态选择加载对应分辨率的图片,像 iphone4 之前老机型使用的是 @1x 的原始图片,而 retina 显示屏出现之后每个像素点被分成了四个像素,因此同样尺寸的屏幕需要4倍分辨率(宽高各两倍)的 @2x 图片,最新的针对 iphone6/6+ 以上的机型则需要 @3x 分辨率的图片。例如下面所示应用的 AppIcon,需要根据机型以及机型分辨率动态的选择加载某张具体的图片资源:
  • 可执行代码模块的加载:例如,在运行时创建一个新类,只需要3步:

    • 为 class pair 分配存储空间 ,使用 objc_allocateClassPair 函数。
    • 增加需要的方法使用 class_addMethod 函数,增加实例变量用 class_addIvar。
    • 用 objc_registerClassPair 函数注册这个类,以便它能被别人使用。

3.参考

  • 深入Objective-C的动态特性
  • 【iOS沉思录】Objective-C语言的动态性总结(编译时与运行时)
  • 编译器做些什么?

原文地址:iOS开发笔记(六):Objective-C动态特性-蒲公英云

Objective-C动态特性相关推荐

  1. 测量功率MOS,IGBT动态特性的双脉冲方法

    ▌01 动态特性   近期,关于用于全国大学生智能车节能信标组的 100W无线充电系统 正在测试.使用 MOS半桥 作为发送线圈的功率驱动电路.由于半桥电路中MOS管的功率消耗主要发生在开关管的动态切 ...

  2. SP-45ML光电二极管放大电路及其动态特性

    ■ 实验背景 在 SP-45ML光电管 放大器模块中,给 SP-45ML光电二极管 增加了基于 AD8606 的运放小板.可以对 LED的电流与光强之间的关系 进行测量.大体可以看到输出的电压与光强之 ...

  3. 【Groovy】Groovy 动态语言特性 ( Groovy 语言与 Java 语言执行效率对比 | 以动态特性编译的 Groovy 类 | 以静态特性编译的 Groovy 类 )

    文章目录 一.以动态特性编译的 Groovy 类 二.Groovy 语言与 Java 语言执行效率对比 三.以静态特性编译的 Groovy 类 一.以动态特性编译的 Groovy 类 Groovy 类 ...

  4. 动态性是Java的特性吗_Java的动态特性有哪些?

    Java的动态特性有两种,一是隐式的:另一种是显示的.隐式的(implicit)方法就是当程式设计师用到new 这个Java 关键字时,会让类别载入器依需求载入您所需要的类别,这种方式使用了隐式的(i ...

  5. (译)Objective-C的动态特性

    这是一篇译文,原文在此,上一篇文章就是受这篇文章启发,这次干脆都翻译过来. 过去的几年中涌现了大量的Objective-C开发者.有些是从动态语言转过来的,比如Ruby或Python,有些是从强类型 ...

  6. PHP语言的动态特性-Going dynamic with PHP

    原文链接: http://www.ibm.com/developerworks/xml/library/os-php-flexobj/ PHP5引入的面向对象的编程特性显著的提升了PHP语言的层次.不 ...

  7. MOSFET开通特性(2)——动态特性

    2.MOSFET的动态特性 2.1驱动电路 驱动电路的暂态模型 Rg上的电压波形: 栅极的输入特性为容性,开通时充电,关断时放电:Rg起到限流和控制开关速度的作用. 2.2栅极的充电曲线及开通关断过程 ...

  8. MATLAB自动控制:分析系统动态特性(超调量,上升时间,峰值时间,调整时间)和静态特性(稳态误差)

    之前看到过一篇介绍已知传递函数分析系统动态特性和静态特性的博客,但那个代码只能分析标准形式的传递函数,最终响应值为1,然而,如果传递函数化为标准形式之后分子上还有常系数,则其最终响应值不为1,用原代码 ...

  9. 步进电机基础(6.2)-步进电机的特性测量方法-动态特性的测量法和步距角度精度的测量

    步进电机基础(6.2)-步进电机的特性测量方法-动态特性的测量法和步距角度精度的测量 前言 基本信息 前言说明 6.2 动态特性的测量法 1 . 滑轮平衡法 2 . 磁滞制动法 3 . 利用扭力棒转矩 ...

  10. 直流双闭环调速系统的计算机仿真,直流电动机双闭环调速系统的动态特性研究与仿真.doc...

    直流电动机双闭环调速系统的动态特性研究与仿真.doc I直流电动机双闭环调速系统的动态特性仿真研究摘要直流电动机具有良好的起.制动性能,宜于在大范围内实现平滑调速,并且直流调速系统在理论和实践上都比较 ...

最新文章

  1. gcc和g++是什么,有什么区别?
  2. php mysql两个表合并_php – 我可以将两个MySQL查询合并为一个吗?
  3. Visual Transformers: Token-based Image Representation and Processing for Computer Vision
  4. python web 开发框架之Bottle
  5. java 故障排查_java线上服务问题排查
  6. 网站关键词优化从这几方面下手效果会更好!
  7. numpy.transpose()转置失败的问题
  8. Linux修改终端显示前缀及环境变量
  9. html5语音云,搜狗语音云开放平台
  10. oracle不一致性关闭下次,Oracle DataGuard
  11. Python验证码简单实现(数字和大写字母组成的4位验证码)
  12. 比特币市值占比达到年内高点
  13. 批处理(bat)没有后缀的文件怎么复制?
  14. zjufantasy.com开发日记(1)
  15. Java基础-刘意经典版DAY1
  16. windows10远程桌面 删除IP记录
  17. fw150rm刷openwrt固件_迅捷FW150R刷TP741N后再刷Openwrt和DDWRT以及固件还原
  18. 淘宝首页中meta标签的作用整理
  19. 计算机专业英语 9次作业合集 从第九次到第一次
  20. 小酷智慧地图3D导览v1.0.84 打卡定位 地图打卡

热门文章

  1. 注意力机制最新综述解读(last revised 12 Jul 2021)
  2. 自定义TTF多语言版本之台湾繁体
  3. Excel中实现模糊查询-LOOKUP+FIND函数
  4. cadence验证仿真工具IUS和IES
  5. kwgt使用的是什么计算机语言,kwgt最新版
  6. 建设可持续社区离不开物业,你们小区的物业怎么样?
  7. IT机房运维技术五大体系
  8. 思维导图制作软件推荐,怎样使用软件绘制思维导图
  9. Vue 3.3 正式发布 [浪客剑心]
  10. 重装win10操作系统