众所周知,Objective-C 是一种运行时语言。运行时怎么来体现的呢?好比一个对象的类型肯定,或者对象的方法实现的绑定都是推迟到软件的运行时才能肯定的。而运行时的诸多特性都是由Runtime 来实现的。objective-c
Runtime 其实就是一套C语言API库,所以它的实现也仍是C语言。若是你想看Runtime的实现源码,能够去官网下载:objc4-646.tar.gz(我看的是这个)。数组
本篇不打算介绍objc_msgSend,可是关于OC中的消息最终怎么被转化为objc_msgSend这个过程,仍是有必要找一篇文章好好的看一下。安全
如下内容部分摘录自:bash
王巍 (@onevcat) 的 深刻Objective-C的动态特性app
Bang 的如何动态调用 C 函数函数
若是你以为看的不尽兴,能够去看下这两篇文章。ui
在开始介绍runtime 以前,先讲讲动态特性。常常被提到和用到的有三种:spa
先来讲说动态加载 ,动态加载就是根据需求加载所须要的资源。 有一个典型的例子,就是iPhone 会根据机型的不一样加载不一样的图片。iOS 下通常会有xxx.png、xxx@2x.png、xxx@3x.png,iOS 应用会在非retina设备上加载1倍图,在retina小尺寸设备(如四、4s、五、5c、5s、六、6s)上加载@2x图片,而后在大屏retina 设备(如6+、6s+)上加载@3x的图片。.net
而后再来讲说动态类型,即运行时再决定对象的类型。动态类型这个特性在平常开发中很是的常见,最简单的就是id类型。稍微经常使用的就是某个类和其子类的类型肯定。指针
id类型即通用的对象类,任何对象均可以被id指针所指,而在实际使用中,每每使用introspection来肯定该对象的实际所属类:
id obj = someInstance;
if ([obj isKindOfClass:someClass])
{
someClass *classSpecifiedInstance = (someClass *)obj;
// Do Something to classSpecifiedInstance which now is an instance of someClass
//...
}
复制代码
-isMemberOfClass:
是 NSObject
的方法,用以肯定某个 NSObject
对象是不是某个类的成员。与之类似的为 -isKindOfClass:
,能够用以肯定某个对象是不是某个类或其子类的成员。这两个方法为典型的introspection方法。在肯定对象为某类成员后,能够安全地进行强制转换,继续以后的工做。
动态类型有利有弊,有了动态类型,咱们能够在运行时根据对象的类型不一样执行不一样的逻辑代码;可是也致使一些错误不能及时的发现。
好比,咱们常常会遇到的这类错误:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[_NSZeroData count]: unrecognized selector sent to instance 0x7f8632ed7ab0'
复制代码
这是错误的示例代码:
基于动态类型,在某个实例对象被肯定后,其类型便被肯定了。该对象对应的属性和响应的消息也被彻底肯定,这就是动态绑定。在继续以前,须要明确Objective-C中消息的概念。因为OC的动态特性,在OC中其实不多说起“函数”的概念,传统的函数通常在编译时就已经把参数信息和函数实现打包到编译后的源码中了,而在OC中最常使用的是消息机制。调用一个实例的方法,所作的是向该实例的指针发送消息,实例在收到消息后,从自身的实现中寻找响应这条消息的方法。
关于传统的函数编译时,把参数信息和函数打包进编译后的源码,以及调用过程,能够参看:Bang的如何动态调用 C 函数 OC 的编译过程之因此不同,是由于在汇编过程,被苹果本身写的汇编接管了。
动态绑定所作的,便是在实例所属类肯定后,将某些属性和相应的方法绑定到实例上。这里所指的属性和方法固然包括了原来没有在类中实现的,而是在运行时才须要的新加入的实现。
在Cocoa层,咱们通常向一个NSObject对象发送-respondsToSelector:
或者-instancesRespondToSelector:
等来肯定对象是否能够对某个SEL作出响应,而在OC消息转发机制被触发以前,对应的类的+resolveClassMethod:
和+resolveInstanceMethod:
将会被调用,在此时有机会动态地向类或者实例添加新的方法,也即类的实现是能够动态绑定的。
一个例子:
void dynamicMethodIMP(id self, SEL _cmd)
{
// implementation ....
}
//该方法在OC消息转发生效前被调用
+ (BOOL) resolveInstanceMethod:(SEL)aSEL
{
if (aSEL == @selector(resolveThisMethodDynamically)) {
//向[self class]中新加入返回为void的实现,SEL名字为aSEL,实现的具体内容为dynamicMethodIMP class_addMethod([self class], aSEL, (IMP) dynamicMethodIMP, “v@:”);
return YES;
}
return [super resolveInstanceMethod:aSel];
}
复制代码
固然也能够在任意须要的地方调用class_addMethod
或method_setImplementation
(前者添加实现,后者替换实现),来完成动态绑定的需求。
关于动态绑定,个人理解例子是:
假设程序里有Person这么一个类,它有name、age、height 以及方法-eat(假设除name、age、height 和-eat 外,其余的属性和方法忽略),而后咱们在某处建立了Person这个实例对象。
刚开始这个实例对象就像白纸同样干净,不知道它的具体类型,也没有属性和方法。而后在动态类型阶段,肯定它的实际类型。再通过动态绑定,才会为其绑定相应的属性和方法,这时候这个对象才算完整了。
关于runtime 的一些基础知识就先到这里了。