杂谈Apple Swift

Apple的WWDC在昨天圆满结束,期望iPhone6的同学可能很失望,但是对于程序员们,他们又多了好多新玩具。除了成堆的新API,Apple还发布了一款全新的编程语言——Swift

早就有谣言Apple会想办法替换掉ObjectiveC,但大家都没当回事。可这次,Apple直接放了大招。

并不是Apple喜欢折腾,是ObjectiveC的确不招人喜欢:

  1. 作为一个C语言的变种,它有较为陡峭的学习曲线
  2. 缺乏动态特性。虽然新版的ObjectiveC已经非常努力的更新很多看起来很NB的东西,但是这在其他语言确实天生支持的。
    1. Java直到8才支持lamda,但ObjectiveC的2013年就支持Block了。不过Block的限制太多,而且语法丑陋
    2. idinstancetype这些东西的产生都是很无奈的,没法彻底解放复杂的类型申明
    3. 说好的generic和auto-boxing呢
  3. [[ObjectievC 的语法] 太罗嗦]
  4. …(欢迎补充)

Swift发布后,我第一时间下载了免费的教程,看完了Language Guide后写下我第一篇关于Swift的文章。

可以预料,网上已经有很多文章在说Swift又如何如何的好了。它到底好不好,我们这打个问号。先让说说它十分有特色的地方,顺便附上免费吐槽。

Swift的产生

Swift is a new programming language for iOS and OS X apps that builds on the best of C and Objective-C, without the constraints of C compatibility.

我们解读下Swift编程指南中开篇的第一句话:

  1. 它是为了编写iOS和OSX的应用而产生的
  2. 它吸取了C和ObjectiveC的优点
  3. 它去掉了为了实现对C兼容性而做出的妥协

Swift的产生是面向未来的,并且是冷静分析了当前Apple软件生态圈之后归纳总结出新语言。编程指南的开篇也提到,Apple内部已经使用了Swift多年。

事实上,有LLVM在前,大家应该不难想像Apple可以搞出很多种高级语言出来,反正只要能通过LLVM编译,就能接入Apple的生态体系了。看看隔壁的微软吧,一个.net上面有多少种语言?

Swift也不是Apple的第一次折腾。从Carbon到Cocoa,从MRC到ARC,大家都是含着泪走过来的。其实,Swift也并不能宣判ObjectiveC的死刑,我相信,对于这种翻天覆地的改动,就算一切顺利,也需要一年左右的时间让开发者接受。Apple很可能会观察社区动向,同时对两种语言进行调整,最坏的情况下,有一部分市场的应用仍旧使用ObjectiveC,而另外一部分,尤其是游戏,很可能彻底抛弃ObjectiveC,而使用更敏捷的Swift。

Swift的定位,意味着它有丰富的动态特性,同时拥有静态语言的性能和安全性。你可以通过XCode6的Playground项目进行实验,也可以直接通过Swift编译器进行调试。Swift Compiler位于:

/Applications/Xcode6-Beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift

变量和数据类型

let it be

Swift的所有变量都需要用let或者var声明。这两个关键字的在别的语言广泛存在:ECMAScript(JavaScript、ActionScript)、Go。Swift也并不要求开发者一定需要写明其数据类型,因为编译器有一定能力推断变量的数据类型。

let implicitInteger = 70
let implicitDouble = 70.0
let explicitDouble: Double = 70

注意,这并不是说Swift变成弱类型了。事实上,Swift的变量一旦确定了类型,便不能改变。而且,Swift也不存在隐式转换。例如,如果需要字符串拼接,需要你手动转换:

let widthLabel = label + String(width)

Generics

let emptyDictionary = Dictionary<String, Float>()

ObjectiveC的数据结构最大的诟病就是不支持Generic了。Swift还提供了两个万精油的数据类型:

  1. AnyObject
  2. Any

相当于于void*id了,这些东西联合起来可以说是让大家对数据结构的应用更灵活一些了。

数据类型

除了常见的Int、UInt、Float、Double、Bool之外,它还有目前动态语言喜欢使用的Tuple。

var my2dPosition = (20, 20)
var my3dPosition = (20, 10, 50)

这也意味着,支持返回多个数值和Deconstructing了。

var (a,b) = (10,20)

然后就是Range,一种全闭合,一种半开半闭。

  • 1…3
  • 1..3

函数

好吧,Swift函数也很难看。它看起来像是Go、Ruby的结合体。但从特性上来讲,Swift的函数是非常优秀的。

  • Functions are a first-class type
  • 可变的函数列表
  • Closure
    • 尾部Closure调用
    • 捕获当前作用域
  • Local and external argument names

这部分将开来讲太复杂了。可以说该有的动态语言特性都有了。

流程控制

更严格的if语句在判断条件时,并不考虑0,而只考虑Boolean。

功能无比强大的switch再也不是鸡肋了:

let somePoint = (1, 1)
switch somePoint {
case (0, 0):
    println("(0, 0) is at the origin")
case (_, 0):
    println("(\(somePoint.0), 0) is on the x-axis")
case (0, _):
    println("(0, \(somePoint.1)) is on the y-axis")
case (-2...2, -2...2):
    println("(\(somePoint.0), \(somePoint.1)) is inside the box")
default:
    println("(\(somePoint.0), \(somePoint.1)) is outside of the box")
}
// prints "(1, 1) is inside the box

enum、class、struct

enum放在这里,是因为Swift里面的enum的确都是一个类了。

enum Rank: Int {
    case Ace = 1
    case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten
    case Jack, Queen, King
    func simpleDescription() -> String {
        switch self {
        case .Ace:
            return "ace"
        case .Jack:
            return "jack"
        case .Queen:
            return "queen"
        case .King:
            return "king"
        default:
            return String(self.toRaw())
        }
    }
}

面对如此凶残的enum我们怎么把持的住?

Swift的类继承可能时Swift里最接近C、C++的地方了。无论是它的默认构造函数、解构函数,还是它后面提到的操作符重载都是C的那套思想,只是表现形式换了下。这意味着,这些东西很麻烦。

而同时又有动态语言常有的gettersetter那套。

struct Rect {
    var origin = Point()
    var size = Size()
    var center: Point {
    get {
        let centerX = origin.x + (size.width / 2)
        let centerY = origin.y + (size.height / 2)
        return Point(x: centerX, y: centerY)
    }
    set(newCenter) {
        origin.x = newCenter.x - (size.width / 2)
        origin.y = newCenter.y - (size.height / 2)
    }
  }
}

每个Property还有两个特殊的observer:

class StepCounter {
    var totalSteps: Int = 0 {
    willSet(newTotalSteps) {
        println("About to set totalSteps to \(newTotalSteps)")
    }
    didSet {
        if totalSteps > oldValue  {
            println("Added \(totalSteps - oldValue) steps")
        }
    }
    }
}

其他的如ProtocolExtension什么的依旧是有的,并且,两者都可以当做Type作为声明变量。

Optional Type

还不知道这个东西该怎么翻译成中文,直接上代码吧:

if let johnsStreet = john.residence?.address?.street {
    println("John's street name is \(johnsStreet).")
} else {
    println("Unable to retrieve the address.")
}
// prints "Unable to retrieve the address."

一个值要么存在,要么为nil。和if一起使用被成为Optional Binding

这恐怕是Swift里最晦涩的概念了。由于Swift里没有指针,而ObjectiveC里一个默认行为就是向nil对象的调用(发送消息)是没有任何效果,这个特点要完整迁移到Swift里是很困难的。Optional Type的确提供了这个可能, 但这也恐怕是Swift学习成本最大的地方了。

与Cocoa和CocoaTouch的混用

Swift可以和Cocoa、CocoaTouch进行文件级别的混用,也就是说你的项目里可以同时存在这两种文件。在Swift里使用Cocoa的API也是可以的:

let dataViewController = storyboard.instantiateViewControllerWithIdentifier("DataViewController") as DataViewController

Apple通过了复杂的桥接实现了这些,但可以远见之后会有很第三方多框架兼容性问题了。

Swift已经不支持C和C++代码的混用了,要记住这是Swift产生的初衷之一。

期望和展望

个人预测它的流行程度很快会超过Go、Ruby,并与Python并排,之后会稳定上升,最终是否会超过ObjectiveC,甚至接近Java,都需要看Apple的布局了。

XCode6内目前是支持以两种不同的语言来编写应用的,但不知道未来是否会慢慢淘汰ObjectiveC。Apple完全有能力维护两套语言,问题在于它是否需要。在很多领域,开发者早就渴望一种充满动态语言特性的开发语言了,想想iOS上那些内嵌Lua的应用吧。

但是,我觉得Swift并不该像它的前辈那样停留在编写几个iOS或者Mac应用上面,它应该走出来,成为真正意义上的通用语言。

    原文作者:RobinQu
    原文地址: https://segmentfault.com/a/1190000000532286
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞