详解Objective-C runtime

原文地址:http://blog.securemacprogramming.com/2013/12/by-your-_cmd/php

 

感谢翻译小组成员wingpan热心翻译。本篇文章是咱们每周推荐优秀国外的技术类文章的其中一篇。若是您有不错的原创或译文,欢迎提交给咱们,更欢迎其余朋友加入咱们的翻译小组(联系qq:2408167315)。html


本文是我在 Alt Tech Talks: London 上关于 Objective-C runtime的演讲总结,若是你对Objective-C runtime感兴趣的话,应该看看这篇文章,特别是文章中的连接,必定会受益不浅。 ios

 

什么是Objective-C runtime?程序员

简单来讲,Objective-C runtime是一个实现Objective-C语言的C库。对象能够用C语言中的结构体表示,而方法(methods)能够用C函数实现。事实上,他们 差很少也是这么干了,另外再加上了一些额外的特性。这些结构体和函数被runtime函数封装后,Objective-C程序员能够在程序运行时建立,检 查,修改类,对象和它们的方法。编程

 

 除了封装,Objective-C runtime库也负责找出方法的最终执行代码。当程序执行[object doSomething]时,不会直接找到方法并调用。相反,一条消息(message)会发送给对象(在这儿,咱们一般叫它接收者)。runtime库 给次机会让对象根据消息决定该做出什么样的反应。Alan Kay反复强调消息传递(message-passing)是Smalltalk最重要的部分(Objective-C根据Smalltalk发展而来),而不是对象: 数组

 

因为之前关于这个话题我创造了“对象”这个词,如今不少人都对这个概念趋之若鹜,这让我感到很是遗憾。缓存

 

其实这里面更为重要的理念是“消息命令”(messaging),这才是Smalltalk的核心内容(如今尚有一些内容尚未所有完成)。日 语中有个简短的单词叫作“ma”,它用来表示两个物体之间的东西,在英语中和它最相近的单词也许是“interstitial”。制造一个庞大且可扩展系 统的关键是设计它各个模块之间的通讯方式,而不是关注它的内部属性和行为。 app

 

 

实际上,在一篇介绍Smalltalk虚拟机的文章里,这门编程技术被叫作消息传递或者消息传送范式。“面向对象”一般用来描述内存管理系统。异步

 

在演讲和文章中都使用ObjC runtime这个词,看似只有一个,实际上存在不少runtime库。虽然它们都支持对象的自省检查和消息接收,可是它们却有不一样的特性和实现方式(例 如,一样是发送消息,Apple的runtime用一步完成,而GNU runtime会先查询这些消息,而后执行查找到的函数分两步完成)。如下全部的讨论,都是基于Apple的最新runtime库(苹果公司在OSX 10.5和iOS发布时的版本)。 ide

 

在那次演讲中,我决定研究runtime库某些领域的功能。我找了一些但愿更透彻了解的东西,而后把它们作成问答的形式组成个人演讲。

 

动态建立类

 

如何实现Key-Value Observing?

 当我在准备此次演讲时,一篇叫作KVO considered harmful 的文章开始拥有不少拥趸。它提出了不少对KVO正确的批评,但相对于舍弃观察者模式不用,我更想探索出一种新的实现方式。 

 

KVO实现观察者模式的关键是它偷偷摸摸将被观察对象的类改变了,它子类化原来的类后,就可以自定义该对象的方法来调用KVO的回调方法。这些都是经过 objc_duplicateClass这个方法完成,但很遗憾,这个方法并不公开,咱们没法私自调用。 

 

条条大路通罗马,好在除了objc_duplicateClass,还有其余方法能够经过使用秘密子类化的方式实现观察者模式,好比建立和注册 “class pair”。那么什么是class pair呢?对于Objective-C的类来讲,都有一对Class的对象来定义它:Class对象定义了这个类的实例方法,而metaclass定义 了这个类的类方法。因此每一个class实际上是它metaclass的单例。 

 

这个代码展 示了观察者模式的工做原理。当你给对象增长观察者时,这个对象首先会检查本身是否可被观察,若是是,它会新建立一个类,用咱们本身的-dealloc替代 原来类的方法,一样它也会把-class方法替换掉,相似于KVO被观察对象,当你访问被观察对象的类名时,返回的是它原来的类名,而不是新生成的类。

 

建立完类后,咱们须要照着 Key-Value Coding为属性增长一个setter方法:这个setter方法会获取这个属性修改前的值和修改后的值,而后调用block形式的回调函数,将这两个值告诉观察者。代码中根据咱们的意愿,这个block能够异步调用。 

 

请注意, -addObserverForKey:withBlock:会使用s object_setClass() 将被观察对象的类替代为新组建的类。这样作最主要的目的是将消息转变为方法的方式改变,可是这须要很是当心,原来的类和新的类必须有相同的成员变量布局。 由于成员变量也是用过runtime访问,修改某个对象的类可能致使runtime没法找到对应的变量。 

 

咱们在存储观察者集合时遇到些麻烦,由于没地方去存它们。给ObserverPattern这个类增长成员变量不起做用,由于根本没有生成这个类的对象。被观察对象的成员变量是它原来类的,它并无考虑过这些观察者。 

 

Objective-C runtime经过引入 associated objects 帮助咱们摆脱这个困境。在runtime里,理论上全部对象均可以拥有包含其余对象的字典。经过associated references,被观察对象能够存储和访问他们的观察者,而不须要额外的成员变量。

 

若是你运行屡次后,你会发现ObserverPattern 仍是有点小毛病的。因为观察者回调是异步调用的,观察者接

 

收到的变化事件也是乱序的。这意味着观察者其实没法区分被观察属性的最终状态是什么,回调中的新值可能早已被修改。我这样作的目的是为了说明在KVO中同步调用回调实际上是个有用的特点,并不是bug。 


建立对象

 

那些额外的字节都是干啥用的?

当你建立一个 Objective-C对象时,runtime会在实例变量存储区域后面再分配一点额外的空间。这么作的目的是什么呢?你能够获取这块空间起始指针(用 object_getIndexedIvars),而后就能够索引实例变量(ivars)。好吧,下面我会使用自定义数组来讲明一下索引ivars的用 处。 

 

让咱们建立一个数组!从这个SimpleArray中能够看到两件事情:最明显的一件是它使用了类簇模式。 当使用+alloc方法返回对象时,通常状况下已经为这个对象分配了全部的内存,可是在这个例子中,在+alloc时并不知道须要多大的内存空间。只有当 调用了 -initWithObjects:count:之后,才能根据数组内对象数量计算出这个数组须要多大的内存,因此+alloc只是返回一个占位符,只有 在初始化后才会分配和返回真正的数组对象。 

 

或许你会问为何咱们要用类簇把事情搞那么复杂,使用 calloc()另外分配一块大小合适的缓存,而后把那些对象指针存到里面不就得了?答案是但愿利用局部性原理提升访问性能。从数组的设计上咱们能够看出,每次数组指针被访问时,以后会有很大概率访问到缓存指针,因此把它们肩并肩的放入内存意味着找到其中一个就是找到了另一个。 

 

消息派发

 

消息如何转发?

Objective-C其中一个强大特性是对象不须要实现某个方法,尽管它在编译时声明了该选择符(selector)。但它能够在运行时再决 定方法实现,或者将这些消息转发给其余对象,或者发出异常,亦或作一些其余事情。可是这个特性的某些方面曾经一直困扰我:消息转发(message forwarding)会调用 -forwardInvocation:,而后传入一个NSInvocation 对象。可是这个NSInvocation 类是在Foundation库中定义的,难道说runtime工做须要Foundation配合? 

 

我试着挖掘其中的缘由,发现答案并非我想的那样,runtime不须要知道Foundation。runtime会让程序定义转发函数 (forwarding function),当 objc_msgSend()没法找到该selector的实现时,那个转发函数就会被调用。程序一启动,CoreFoundation就将 -forwardInvocation:定义成转发函数。 

 

让咱们来建立一个Ruby! 固然并非真的实现完整的Ruby,Ruby有一个叫作#method_missing的函数,当对象收到一个它没有实现的消息时,这个函数就会被调到, 这和Smalltalk的作法比较类似。使用objc_setForwardHandler,咱们也能在Objective-C的类中实现相似Ruby的 methodMissing:方法。 

 

总结

Objective-C runtime能够有效的帮助咱们为程序增长不少动态的行为。一些开发者除了使用method swizzling帮助调试程序,并不会在实际程序中使用它,但runtime编程的确有不少功能,它应该成为实际应用代码编写的重要工具。

相关文章
相关标签/搜索