2
本文作者: 唐天勇 | 2016-06-25 23:06 |
雷锋网按:本文作者唐天勇, iOS研发工程师。欢迎关注其知乎专栏“LeanCloud技术专栏”。
Objective-C是开发OS X和iOS应用的标准语言。即便是天天跟它打交道的开发者,有些也会误以为Objective-C就是Apple公司创建出来的语言,但实际上它并不是Apple的亲骨肉,而是从别人家过继过来的孩子。
程序设计语言是一个规范,它可以有许多种实现。在历史的漫漫长河中也出现过其他Objective-C实现,下面我会主要以Apple的Objective-C实现来论述。
Objective-C的诞生要追溯到1980年左右。那时Brad Cox和Tom Love两位工程师还在ITT实验室工作,他们意识到程序设计语言的抽象程度在软件开发中扮演着重要角色。他们认为Smalltalk在这方面做得非常出色,但执行效率是瓶颈,并且实验室里大部分系统软件都是用C语言实现的,因此他们希望把Smalltalk的好处带到C语言里。Objective-C就是在这样的背景下诞生了。
1983 年,Brad Cox和Tom Love成立了Stepstone公司,并发布了第一个Objective-C实现。据Brad Cox回忆,最初的实现就是个简单的预处理器。他们使用sed和awk等工具把Objective-C直接翻译为C语言。可C语言并不原生支持Objective-C的动态语义,例如dynamic dispatch。动态语义是通过一个library来实现的,这个library逐渐发展成了现在的runtime library(简称 runtime)。
后来Stepstone被Steve Jobs领导的NeXT收购,Objective-C由此迎来它的首次发展。不过NeXT并没有在语言中引入新特性,而是对runtime做了一些优化,即NeXT runtime。
Apple收购了老乔的NeXT后,就把NeXT当时在使用的Objective-C直接继承了过来,即所谓的「Objective-C 1.0」。后来Apple在语言中增加了一些新特性,例如属性、fast enumeration、垃圾回收(后来被ARC取代)。不久前Apple为Objective-C引入了轻量级泛型。这样的改进可谓进步巨大,runtime也被完全重写并开源了出来。 Apple将这一新的实现称为「Objective-C 2.0」,也就是我们现在看到的这个样子。
Apple对语言的持续改进让开发者欢欣鼓舞。Objective-C 2.0也在OS X和iOS应用开发的浪潮中站稳了脚跟。作为语言的使用者,我对Objective-C语言是爱恨交加。一方面,小巧的语言结构、动态的本质让开发变得多姿多彩,特有的方括号也让代码添了几分味道;另一方面,从现代的眼光来看,语言缺乏一些高级特征,比如命名空间 namespace、完整的泛型支持等。虽然仍不完美,但承担起Apple应用开发的重担,它做到了。
早期的Objective-C只支持手动内存管理,开发者必须仔细去跟踪每个对象的生命周期,犹如做针线活一般,步步小心谨慎,否则就会扎破手指。而同时期的许多语言都已开始引入了更高级的内存管理,例如垃圾回收,Java就是其中的典型代表。虽然手动内存管理在执行效率上有优势,但同时也带来了额外的心智负担。好在后来引入了自动引用计数ARC。虽然它的背后仍然是引用计数,但大多数时候不需要开发者跟踪对象的生命周期,而是交由编译器和runtime来做。开发者只需要注意一些特殊情况即可,例如循环引用。
Objective-C不支持namespace,也就意味着它不支持嵌套类,所有符号会在编译阶段连接到一个全局的namespace下。如果连接时发现了重复的符号,编译就会失败。为何Apple迟迟不在Objective-C中引入namespace呢?其实Apple曾多次考虑过这个问题,但发现这是个大坑,填起来困难重重。
困难之一是与C和C++之间的协调。由于Apple允许Objective-C和C++混合编程(Objective-C++),这就要求Objective-C的namespace与C++的保持兼容,然而这是不可能的。另一种选择是只对Objective-C语言实现namespace,不过也有问题。因为Objective-C语言是C语言的超集,C语言没有namespace的概念,其结果只能对Objective-C的类实现namespace。但是Objective-C中的那些方法又会最终编译成C语言的函数,只能对方法做name mangling,这又会导致ABI不兼容。目前Apple尚未找到能完美解决这一问题的方案,Objective-C也只能先感慨着与namespace的缘分未到了。
Objective-C早期不支持匿名函数或者闭包,但随着社区的呼声越来越高,Apple最终为Objective-C增加了这一特性。不过有趣的是, Apple是直接在C语言中实现的,称之为block。Objective-C扩展了block,以适应Objective-C的内存管理。
Objective-C 1.0不支持泛型。直到Objective-C 2.0才引入了轻量级泛型。注意,之所以轻量级是因为它完全由编译器实现,没有runtime参与,泛型信息在代码生成阶段就被丢弃了。可能Apple也不希望在runtime中引入额外的代价吧。
随着OS X和iOS开发生态的繁荣。越来越多的开发者投入到OS X和iOS应用开发中来,社区涌现出许多优秀的第三方库。
第三方库不断积累,包依赖管理亟待解决。可Apple并没有官方的解决方案。既然没有官方的,那就自己动手做一个吧,CocoaPods就是这样问世的。不过由于Xcode的封闭,CocoaPods的开发过程也非常艰难,经常因Xcode的升级而出现不兼容的状况。但CocoaPods最终克服了重重障碍,成为管理依赖的首选。
社区的不断壮大让Objective-C长期占据着TIOBE排行榜前10的位子,所以这门古老的语言在21世纪依然能绽放耀眼的光芒。
2014年一声炮响,Swift横空出世,Apple不遗余力地向世界宣告着这个亲骨肉的到来,而有关继子Objective-C该何去何从的讨论也愈演愈烈。诚然,Swif 解决了Objective-C的许多痛点,例如支持namespace、运算符重载、更轻松的内存管理等。我想,Objective-C不会在短时间内离我们远去,因为社区中还有大量的codebase是用Objective-C写的。并且,Objective-C与 C / C++语言更亲近,如果项目中需要和大量 C / C++交互,Objective-C 仍然会继续发挥余热。
雷峰网原创文章,未经授权禁止转载。详情见转载须知。