您可以捐助,支持我们的公益事业。

1元 10元 50元





认证码:  验证码,看不清楚?请点击刷新验证码 必填



  求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Modeler   Code  
会员   
 
   
 
 
     
   
 订阅
  捐助
从Objective-C到Swift
 
作者 黄兢成 火龙果软件  发布于 2014-07-11
   次浏览      
 

2014年WWDC大会,苹果在毫无预兆的情况下,发布了Swift编程语言。这个语言刚发布就引起了广泛关注。我认为抛开Objective-C单独谈论Swift是不准确的。因此我们先从Objective-C谈起。

Objective-C语言

Objective-C语言是编写iOS/Mac程序的主要语言。编写iOS/Mac程序,除了Objective-C,还可以混合使用C/C++,另外也可以嵌入一些脚本语言。但在UI部分,使用Objective-C最为直接自然。

Objective-C和C++都是C语言的扩展。C++十多年前就已名满天下,而Objective-C虽然也诞生了二十多年,但在iPhone发布之前,一直不温不火。

这两种语言都支持面向对象,设计理念却十分不同。C++的面向对象部分更强调类型,需要知道对象的类型才能调用对象的函数。而Objective-C则更强调消息的发送。另外,C++很看重运行速度,运行时基本不包含类型信息,整个运行环境是静态的。而Objective-C则牺牲了一点运行速度,换来更加灵活、完全动态的运行时环境。

Objective-C的缺点

初学iOS开发,第一个门槛就是Objective-C的语法,它的语法跟主流的语言十分不同。有些人甚至觉得它的语法丑陋得无法忍受。另外,Objective-C的代码看起来比较啰嗦。如同一个人,看起来怪怪的,不太合群,熟悉之后又显得太过唠叨。

Objective-C缺少一些语言的保护机制,成员函数不区分公有私有,且没有命名空间。模块与模块之间需要加前缀来区分,比如Foundation模块类前面都加上NS前缀,表示NextStep。

Objective-C兼容C语言。因此C语言很多设计不合理的地方也被引入了Objective-C中。另外,Objective-C没有采用GC(垃圾回收),它的内存管理采用引用计数的方式,后期引入ARC (自动引用计数),这种内存管理方式相比GC而言,对程序员的要求较高。

当然,Objective-C也有很多优点。甚至可以说Objective-C的某些缺点,从另一角度看,恰恰是它的优点。

Objective-C的优点

  • 动态运行环境,适合UI编程

在Objective-C中,如下语法并非单纯的函数调用,而是向某对象发送消息。

Objective-C的运行环境是动态的,可以在运行时判断出某对象能否响应某种消息,而不管此对象是什么类型。

UI程序大框架就是消息处理。系统接受到某种消息(如程序启动了、列表被选中了、手指在屏幕上移动了)之后交给可以响应这个消息的对象来处理,而不关心这个对象到底是什么类型。

  • 方便与C/C++ 混合使用

Objective-C中的C扩展部分,使用符号@开头。比如@class、@interface、@"Hello,World"。而它的消息发送语法则是使用中括号而不是圆括号。

这种独特而另类的语法使得Objective-C的代码,就算跟C++代码混在一起,也很容易被识别出来。此外,将文件扩展名修改成mm就可以在同一文件中混合使用Objective-C和C++。两者直接相互调用,不用经过任何间接层。在需要大量使用C++的场合(比如游戏),这种混编特性很有用。

  • 运行速度相对较快

Objective-C编译后是机器原生指令,运行时环境也小而紧凑。它采用引用计数的内存管理方式,并引入ARC。ARC比GC更容易引起编程错误,但却比GC快。而在性能很重要的场合,Objective-C也很容易直接调用C/C++代码。相对于其他使用虚拟机、采用GC以及间接调用C/C++的移动平台,速度优势非常明显。

Swift和Objective-C的联系

苹果一直在改进Objective-C,默认编译器由GCC换成了LLVM,并先后加入literal、block、ARC、Module等特性。我认为最大的两点改进为以下两点。

  • ARC+弱引用,本质还是引用计数。但从人手调用retain、release,转成编译器自动插入代码是个质的飞跃。
  • block+GCD,block引入函数式风格的代码块,而GCD则大大简化了异步代码编写方式。

WWDC之后,我开始思考一个问题,苹果为什么不继续改进Objective-C,而发布Swift这门新语言呢?这个问题只有苹果自己知道,其他人只能猜测。

可能的原因有以下几个方面。

  • Swift表面看起来很简单,语法跟流行的C#、JavaScript、C++等语言相似,可以吸引更多的开发者。
  • Objective-C因为需要兼容C,所以限制了它的改进。而Swift没有历史包袱,可以自由采用最新的语言设计研究成果。
  • 设计者的个人品位,Chris Lattner不习惯Objective-C的语法,就去设计了一个新的。当然,这是玩笑话,不要太当真。

Swift虽然是新语言,却融合了Objective-C的很多特性。读Swift的文档会发现,Objective-C与Swift的联系十分密切。Objective-C使用的很多底层技术,被应用到Swift中。

Swift与Objective-C共用同一套运行时环境

我们编写程序,让程序运行起来,被机器执行的代码并非全部是由我们自己来编写的。需要同时运行很多预先写好的支持性的代码,才能让我们自己的代码运行起来。程序并非单独存在的,运行时处在一定的环境当中。我总联想到很多小蚂蚁在泥土上面爬,而我自己写的程序只是其中的一只。

Swift跟Objective-C编译出的程序代码运行在同一套运行环境上面。Swift的类型可以桥接到Objective-C的类型,反之亦然。Swift编写的代码可以调用Objective-C编写的代码,反之也一样。

Objective-C之前积累下来的大量类库,实现不用改写Swift就可以直接调用。

同一个工程,可以同时使用Swift和Objective-C

Objective-C在一端,Swift在另一端,两端经中间文件进行桥接。桥接文件包含Objective-C的头文件,编译时自动转成Swift可以识别的形式。Swift就可以使用Objective-C的类和它的函数。

在Swift的类中,加上@objc(类名)的字样,Objective-C也可以使用Swift编写的类。但Swift跟C++的相互调用,需要Objective-C来封装。

总的来说,共同使用Swift和Objective-C/C++还算方便,但已不能将几种语言的代码,混写在同一文件。大概是因为Swfit的语法不像Objective-C那样独特,混写难以将Swift的代码识别出来。

Swift骨子里大多与Objective-C一样

Objective-C出现过的绝大多数概念,比如引用记数、ARC、属性、协议、接口、初始化、扩展类、命名参数、匿名函数等,在Swift中继续有效(可能只是换了个术语)。我自己将Swift看成是Objective-C的一块大大的语法糖,其他人可能有不同感受。

Swift大多数概念与Objective-C一样,也有些概念在Objective-C找不到对应,比如泛型。Swift中将那种操作写一次就可以作用多个类型的语法叫做Generics(泛型)。

编程语言和语法

新语言出来时,总会有种声音认为语言只是工具,他们会觉得重要的是思想,而看轻工具的作用。认为编程语言是工具本身并没有大错,但语言并非普通的工具,而是思维工具,不能忽视语言对思维的影响。编程语言就如同数学符号,数学符号也是种思维工具,好的数学符号会帮助使用者思考,更奇妙的是似乎符号本身也会思考。用0~9这些阿拉伯数字进行计算时会感到一切都很自然,似乎数字本身在计算,而不是人在做计算。

尽管编程语言的语法很重要,但语法背后的概念更重要。当明白语法背后的概念后,从一门语言切换到另一门有着相同概念的语言会很容易。但语法会影响表达,理论上每门语言都可以表达任何概念。不过当某种概念在某门语言中很难表达出来时,我们就会倾向于不使用它,这种概念在那门语言的社区就难以被人熟知。

编程语言用来表达思路,表达起来是否自然是很重要的。最理想的是不多不少、刚刚好,写起来自然,读起来更需要自然。并非功能越多的语言越好,而是应该越能帮助思考,越容易表达思路的语言越好。

Swift背后的概念大多跟Objective-C差不多。但Swift吸收了很多其他语言的语法,同一个概念,写起来比Objective-C简洁得多、自然得多。从表达的角度来说,Swift比Objective-C优秀。

Swift的语法

苹果出了本很不错的语法教程来详细描述Swift的语法。在这里,我们只挑一些有意思的点来讨论。

简洁

Swift的语法给人第一感觉就是简洁干净。如果省略掉也不引起歧义,那符号基本上可以被省略。

我们来看下面这个例子:

Swift写起来,有点像脚本语言。这里没有出现类型定义,有人觉得它就是脚本语言,是解释执行的。而实际上Swift是真正的编译语言,通过类型推导,变量的类型可以确定下来。既然省略掉类型也不引起歧义,也就可以省略了。上面的例子中,传统的句末分号可以省略;循环中的()也可以省略;循环1是C语言中的传统写法;i作为计数变量;循环2是循环1的等价写法,因为根本不用关心计数变量,因此可以直接写成“_”。

不再兼容C语言,修正Objective-C中容易出错的地方

例子1

在C/Objective-C中,if、while、for之后的判断式并不需要一定传入布尔类型。也可以传入整型、指针等类型,只要非0就为真,并且赋值是有副作用的。比如:

上面代码返回a的数值,这样就有可能出现将判断:

错写成:

为避免这个问题,有种变通写法:

这种写法被称为Yoda表达式,因为《星球大战》中的Yoda大师喜欢使用这样奇特的倒装句子。

Swift强制要求if、while、for后面判断式子一定需要传入布尔类型,并且赋值没有副作用。因此写成以下这种判断就会编译错误。Yoda表达式这种变通写法再也没有必要。

例子2

还是拿判断来说。在C/Objective-C中,if、while、for之后的语句假如只有一行,是可以省略掉大括号的。比如:

当后面的人修改代码,或多人修改同一代码再合并时,可能会在if后面直接插入一行,这样就一定会goto fail了:

在Swift中,强制要求if、while、for之后一定需要写大括号,不管是不是只有一行。这样就避免了上述问题。

不难看出,Swift的语法设计使一些C/Objective-C常见错误不可能再出现。

常用类型集成到语言里面,而非以库的形式提供

有几种类型,几乎每个项目中都使用到了,分别是:整数、浮点数、布尔型、空值;字符串;数组、字典。

对这些类型的支持,每个语言都有所不同。有些老旧的语言不支持浮点;有些语言中,布尔和空值是整数的一种;有些语言中,整数和浮点数合并成一类,统称为Number;有些语言中,并没有字符串、字典、数组;有些语言中,字典和数组归成一类。

语言不提供的类型多数以库的形式提供。比如在C++中,语言内部并没有提供字符串、字典、数组,但这些类型却出现在了标准的库中。使用库的形式来提供常用类型,优点是减少语言自身的复杂度,另外库可以自由替换。而采用语言直接支持的方式,使用起来会很简洁流畅。Swift中的常用类型集成到了语言内部。 数组写成:

字典写成:

这种写法在原来的Objective-C中就已出现,现在融入到了Swift中。

此外,Swift还支持另外两种类型:option和tuple。option表示有值或根本无值;tuple则表示多个值,它可以从函数中返回多个值,或一行代码交换两个值。

在C++中,这两种类型也采用库的方式来提供。std::tie与std::tuple结合,可以达到返回多重值的效果,但显得语法噪音多、不够方便,所以也比较少用。

支持多种编程泛式

将Swift分拆开,可大致分成以下部分:基本类型、控制流、函数定义和调用、函数式编程、面向对象、泛型。

实际上,Swift的内容包含很多,也可以说很复杂,并非表面上看起来那样简单。Swift从语法上直接支持现代流行的编程泛式,包括:结构化编程、函数式编程、面向对象、泛型。每个部分Swift都有些闪光点,在此无法一一述说。

值得一提的是,我特别喜欢它的函数式编程部分。接下来我们直接拿文档的一个排序例子,看看它是怎么简化编程的。

最开始版本,传递函数

使用闭包

推导出参数类型,参数类型省略

推导出返回类型,return省略

省略掉闭包里面变量

假如闭包是函数的最后一个类型,可以将{}提到外面

使用操作符函数,最后版本

很好地支持内部DSL

有一种编程风格不太好归类,就是将程序拆分成“描述+解释”。解释部分写一次,其他地方使用描述式的语句,而不是命令式的语句。

内部DSL,通常利用主语言的语法特性创造出一套写法来写一些描述性的语句。这些语句组合起来就像一门新语言似的。举个从Ruby那里借过来的例子。假如计算几小时之后的秒数,C语言中大致会写成:

而现在Swift中定义了扩展:

因此可以写成(分别是3小时后的秒数和3小时前的秒数):

同理,也可以写成:

这种写法看起来跟原来的命令式写法完全不同。这些语句是描述性的,而原来的Objective-C做不到这一点。估计Swift以后会冒出大量这样风格的库。至于这种风格到底好不好,要看具体情况。据我所知,比较方便定义内部DSL的语言,原来有C++、Ruby、Lisp,而现在又多了Swift。

Swift的语法还有很多有意思的地方。比如属性的中get、set写法;switch case中的模式匹配;泛型中的类型约束等。这里不一一细说了。

Swift的争议

下面列出一些Swift争议性较大的地方:

  • 东抄西抄一些语法、大杂烩,没有自己的原创;
  • 没有一些private、protected之类的权限控制;
  • 没有采用GC(垃圾回收),却采用ARC(自动引用计数);
  • 没有异常处理;
  • 是否可以跳过Objective-C,直接学习Swift。

对这些争论,我们很难作出客观的评价,更不可能武断地下结论。我感觉Swift这门语言还是比较有意思的(有些人写程序只是单纯为了好玩)。

这里特别提一下异常处理。以往我一直觉得异常处理是很好的特性,现在觉得异处理常并非一定是好的。异常处理的问题在于发生异常的地方与处理异常的地方分离开来,真正处理时难以收集到足够的信息。异常也容易滥用,很多初学者的Java代码,只抛出异常而不处理,或干脆在最外层接收所有异常,再打印出异常信息。这样也就失去了异常处理的意义。Objective-C中也有异常处理的功能,但实际上几乎没有人使用。对于Swift,采用多返回值加上option的方式来处理错误可能会更好。

可视化编程

WWDC发布会上演示了Swift的Playground功能。敲入代码,立即有反馈。当我们每一步操作都得到实时的反馈时,我们的做法会有很多不同,做出的东西也会有不同。可视化编程放到最后,并非是表示它不重要,而是它实在太重要了,只是目前有能力评说的人还不多。关于这部分内容, Bret Victor有几个演讲视频和文章,建议大家看看。

Swift还有很多主题,只能靠大家自己研究了。最后拿出本次WWDC的Slogan与大家分享:Write the code,Change the world。

   
次浏览       
 
相关文章

手机软件测试用例设计实践
手机客户端UI测试分析
iPhone消息推送机制实现与探讨
Android手机开发(一)
 
相关文档

Android_UI官方设计教程
手机开发平台介绍
android拍照及上传功能
Android讲义智能手机开发
相关课程

Android高级移动应用程序
Android系统开发
Android应用开发
手机软件测试
最新活动计划
LLM大模型应用与项目构建 12-26[特惠]
QT应用开发 11-21[线上]
C++高级编程 11-27[北京]
业务建模&领域驱动设计 11-15[北京]
用户研究与用户建模 11-21[北京]
SysML和EA进行系统设计建模 11-28[北京]

android人机界面指南
Android手机开发(一)
Android手机开发(二)
Android手机开发(三)
Android手机开发(四)
iPhone消息推送机制实现探讨
手机软件测试用例设计实践
手机客户端UI测试分析
手机软件自动化测试研究报告
更多...   

Android高级移动应用程序
Android应用开发
Android系统开发
手机软件测试
嵌入式软件测试
Android软、硬、云整合


领先IT公司 android开发平台最佳实践
北京 Android开发技术进阶
某新能源领域企业 Android开发技术
某航天公司 Android、IOS应用软件开发
阿尔卡特 Linux内核驱动
艾默生 嵌入式软件架构设计
西门子 嵌入式架构设计
更多...