稀有猿诉

十年磨一剑,历炼出锋芒,说话千百句,不如码二行。

Introduction to Swift

Swift是水果平台新引进的一个开发语言,可以用它来取代Objective-C来开发Mac OS X以及iOS上面的应用程序。这门语言引入了大量的具有时代气息的新型编程语言特性,具有动态语言的简洁方便,是未来的发展方向。这是一门新的语言,今年六月才问世,所以如果今天开始学习Swift,三五年后,孤将是“有着五年经验的Swift砖家”了,错过了C,C++,Java,Python等,这回可以跟所有人站在同一起跑线上了。

必备的工具

很显然,要想玩水果的东西,就必须有Mac电脑,而且XCode 6和以后的版本才支持Swift,而XCode 6需要Mac Mavericks(10.9)以后的版本才可以。所以,如果是旧的Mac还不一定可行。

孤作为穷人,无法支付死贵死贵的Mac机,所以只能用虚拟机对付了。VMWare可以搞定一切,具体方法请百度,网络上面有很多已经安装好的VMWare的Mac镜像,下载解压后就可以使用。等发达了,孤再买Mac。

其实,如果你只是想学习Swift,而不是iOS或Mac开发,那么完全没有必要这么麻烦,用一个浏览器就能搞定,SwiftStub是一个在线即时Swift编译器,用起来相当爽。

至于教程,看官方的就好了,浏览器(网站),iBooks都可以方便的看到。

这方面,水果比谷歌强多了,更为重要的是水果在中国访问无压力,谷歌就蛋疼了,上半年Android的文档都无法访问,现在Android源码也时常抽风,不说了。

初体验

先来个高大上的第一个程序:

1
println("Hello, world")

我想都能猜出来会输出啥吧。 建议把A Swift Tour的代码全都敲一遍,虽然可能你没有理解,至少有个初级印象。

基本语法结构

可以说Swift与Python的语法结构是比较接近。每一行语句结尾处不用写分号。如果一行有多条语句,要用分号隔开。

变量的定义是用var关键字

1
2
var slideCount
slideCount = countSlides()

常量用let关键字

1
let slideLimit = 10

注释与C/C++和Java以及Objective-C是一样的

1
2
3
4
5
let timeout = 20 // in seconds
/**
 * Send a email to destination
 */
sendEmail()

数据类型

这个也跟其他语言没啥大区别,String, Int, Bool, Double等。

运算符号

+, -, *, /, %, &&, ||, !, ==, : ?跟其他语言一致

控制语句

分支,循环跟其他语言也基本一致。只是条件判断的地方,跟Python一样,不用写括号:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
let message = "Who are you"
if message == "Unlock me" {
   // something happen
} else {
   // ignored
}
var i = 0
while i < 10 {
  // sleep for another i mins
}
var done = false
do {
   // continue coding
} while (!done)
let fruits = ["Apple", "Pear", "Cherry", "Peach"]
for f in fruits {
   // eat it
}

函数

函数的形式就是func name()->,括号中放参数,箭头后面是返回值,无参数就是空括号,无返回值不用写箭头。

1
2
3
func countSlides(slide: Slide, mine: Bool) -> Int {
   return 10
}

Swift的特性

除了有所有编程语言所共有的特性以外,Swift有一些比较不太常见的语言特性,是学习的时候需要特别学习和理解的。

选项型变量(Optionals)

可能翻译的不准确。Optionals的意思就是这个变量有一个有意义的值,或者什么都不是。简单来讲,或者通俗的来理解,就是一个对象是不是nil。

Optional的表达方式是在类型后面加个问号,如String?表示一个字串,Int?表示一个整型。

1
2
3
var possibleString: String? // default set to nil
possibleString = "Beijing"
let count: Int? = 0

获取Optional变量的值可以用叹号,如possibleString!就是取它的值。但是如果变量是没有值的(nil),取值时会得到异常。

其实可以用C语言的指针来简单理解这玩意,Optional就相当于指针,取值*操作对于空指针(NULL)肯定会挂。

这玩意这么不好理解,到底有啥用?就是专门用在判断语句中的,可以消除== nil的这种判断:

1
2
3
4
5
6
7
8
var possibleString: String? = "Impossible is nothing"
if let msg = possibleString {
    println(msg!) // or println(msg), they are equal
}
var possibleNumber: Int? = 4
if var cnt = possibleNumber {
   cnt += 10
}

这意思就是如果possibleString有值(不是nil),则赋给msg,并执行分支,等价于如下:

1
2
3
4
5
if possibleString != nil {
   println(possibleString!)
} else {
   println("it is null")
}

怎么样,对于C/C++和Java语言来说,这的确优雅很多。而普通的定义变量的方式就不能这么用。

判断空的操作符

??操作如果操作数是合法值,则返回它的值,否则返回nil,这有啥用?

1
2
3
a ?? b
// is equal to 
a != nill ? a! : b

比如,设置字体大小,默认是32,从用户取值,fallback成默认值,可以这么写:

1
2
3
let defaultFontSize = 32
var userValue: Int? = getUserFontSize()
let fontSize = userValue ?? defaultFontSize

怎么样,又省去了nil判断,优雃了不少。

引用判断操作符

对象的等值性(Equivalence)与指向对象的引用的等值性一直是一个困扰很多人的问题,特别是初学者,对于Java更是这样,很多隐蔽性的Bug都出现在了等值的判断上。对于Java,==是判断引用是否指向同一个对象,而equals方法则是判断二个对象是否相同,而对象的相同则是需要自己去定义的。

同样,这里也是==是检查对象是否相同,而===是检查引用是否相同.

范围操作符

…是范围操作符,类似Python中的range()函数。

a…b是表示[a, b],都是闭区间(希望数学区间的概念都没有忘记)

a..<b是表示[a, b),后面是开区间

必须保证a < b,开始比结束小.

函数外参数名

与Objective-C一样,Swift的函数也支持外部参数名(External Parameter Names),就是调用函数的时候也指定参数的名字,以加强程序的可读性,对于同一类型参数的函数来说特别重要。

1
2
3
4
func countSlide(#slide: Slide, #mime: Bool, #message: String) -> Int {
   /// ….
}
countSlide(slide: aslide, mine: false, message: "Go to bed")

怎么样,这是不是大大的增加了程序的可读性呢!起码我觉得是的。相比Java(或者其他语言):

1
2
3
4
int countSlide(Slide slide, boolean mine, String message) {
    return 1;
}
countSlide(aslide, false, "Not now"); // cannot guess what parameters mean and for

对于函数声明,可以大致明白参数的用途。但是看着函数的调用,完全不知道参数都是用来干嘛的,特别是对于boolean, int等基本的数据类型。

闭包

闭包(Closure)是现代编程语言必不可少一个特性,它能有效的减少代码,减少对成员状态的依赖。这是函数式编程的必要特性,用闭包可以不用成员或者全局变量。

闭包的数学上的定义比较复杂,头发多的人都看不懂。通俗来讲闭包就是所定义的函数或者类持有它所在的定义域内的所有变量,常量和方法的引用。还是有点绕,说白了,就是一个内部定义的函数或者类,持有对外部类的所有成员的引用。

闭包的通常的呈现形式:

  • (匿名)内部类
  • (匿名)内部函数
  • Lamda表达式,通常是指短小的匿名函数
  • 全局类和函数其实也是闭包,只不过它们没有闭合任何外部引用而已

捕获的概念,当闭包引用外部变量时,就称作捕获外部变量。也就是说当你在内部函数里面访问外部变量时,就是在捕获变量。

各种语言中,闭包使用最多的形式就是Lamda表达式,就是一些短小的命名或匿名函数体。这也是闭包的意义所在。

在Swift中闭包的主要形式就是匿名或者命名函数体。对于命名函数体的定义和使用方式跟普通函数一样,只不过可以捕获变量。如:

1
2
3
4
5
6
7
8
9
10
11
12
func makeIncrementor(#step: Int) -> () -> Int {
   var total = 0
   func incrementor() -> Int {
      total += step
      return step
   }
   return incrementor
}
var a = makeIncrementor(step: 10)
a() // 10
a() // 20
a() // 30

但更多时候还是使用匿名函数体或者叫做Lamda表达式,因为这是最方便的。形式:

1
2
3
{ ( **parameters** ) -> **return types** in
  **statements**
}

比如,定义一个遍历数组,并对每一个元素都做某种操作的函数,调用者使用时就可以用闭包来完成这某种操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
func apply(#list: [Int], #action: (Int) -> ()) {
    for item in list {
        action(item)
    }
}

var primes = [2, 3, 5, 7, 11, 13, 17, 19]

// Standard closure
println("Standard closure")
apply(list: primes, action: {(item: Int) -> () in println(item)})

// Simplified by removing return type
println("Removing return type")
apply(list: primes, action: {(item: Int) in println(item)})

// Simplified by removing type
println("Removeing type")
apply(list: primes, action: {(item)  in println(item)})

println("Removing parentheses")
apply(list: primes, action: {item in println(item)})

// Simplified again with shorthand
println("Removing param and use shorthands")
apply(list: primes, action: {println($0)})

如果,闭包是函数的最后一个参数,还有另外一种写法,叫做尾后闭包(Trailing Closure)

1
2
3
someFunction(params) {
   closure goes here
}

如:

1
2
3
4
5
6
7
8
9
10
// With trailing closure
println("With trailing closure")
apply(list: primes) {
    item in
    println(item)
}

apply(list: primes) {
    println($0)
}

结构体

struct几乎与class有同样的功能,都能定义复杂数据结构,添加行为方法,但它们还是有区别的:

最大的区别就是struct是按值拷贝赋值,而class是按引用拷贝。因此,大多数情况下,还是要使用class,效率上至少会有收益。那么为啥还要有struct呢?它适用于Plain old data structure or PoD,也就是说一个纯数据结构,里面全都是基本类型。

其他场合,还是用class吧。 (是不是想起了C++著名的面试题struct vs class)

这才仅仅是冰山一角

这里仅是简单的介绍了Swift的一些语言特性,仅够入门使用,但足可以开始iOS之旅,光有语言还是不够的,对于任何一个平台,编程语言仅能占三成,剩下的大部分还是要学习平台提供的东西,包括开发环境,IDE,和平台提供的API(库)。对于CocoaTouch来说,它跟语言(Swift和Objective-C)基本上是无关的,现在的官方文档的API说明都给出了二种语言的接口,而且Swift和Objective-C基本上可以无缝切换,所以如果已熟悉iOS的框架的,可以轻松转换。

参考及资源

Comments