第三章:了解Swift

在这一章里,我们会学习Swift基本的知识:创建变量,集合,循环体以及条件语句。这一章将会介绍Swift中最重要的知识,这样你能更开的开发程序。

什么是Swift?

Swift是苹果公司开发的新的编程语言,在2014年六月的AWDC上推出的。过去20年里苹果公司使用Objective-C来开发程序,而Swift的推出是为了让编程更加简单明了,为初学者减少了障碍,让所有人都可以开发APP。

Playgrounds

Swift最令人幸福的新特性之一就是Playground,可以快速简单的编写程序,能够立即检测代码正确性。我强烈推荐你在阅读此书的时候,电脑上会一直开着一个Playground文件,写下书中的代码和例子,这样不仅能帮你看到代码是如何运行的,更能提供你的记忆力。 现在,新建一个Playground文件吧(图3-1)。

Page 55

打开Xcode,点击File -> New -> File ,点击iOS下的Source,点击Playground,最后点击Next(图3-2)。

Page 56 | Chapter3:Diving into Swift

本书的每一个章节你都要保存一个Playground文件

选择要保存的文件夹,可以保存在上一章节中已经建好的Programming文件夹,输入文件名,点击Create(图3-3)。现在,你有了一个Playground文件了(图3-4)。

Playgrounds | Page57

模仿本书的代码,试验你的想法,试验是学习新语言的最好方法。本书的代码可以在这里找到:AppSchool.com/book

声明变量(Creating Variables)

变量是可以改变的值,值是动态的。动态意味着一个值可以现在变化,也可以在将来变化。在swift中,用var表示变量,这样Xcode就知道你声明的是一个变量。 变量用变量名表示,变量名关联变量的值,这样就意味着,变量的值发生改变后,变量名是不变的,可以一直用变量名来指示这个变量。变量名的命名方法遵循驼峰命名法。例如: var numberOfYears 在变量名后面跟一个冒号,这是告诉Xcode你要声明的这个变量的类型。类型就类似电影中的分类,有些是喜剧电影,有些是音乐剧、恐怖片、文艺。每个分类都有自己独特的特性,但是它们都是电影。声明变量的类型使用冒号,在冒号后面,写上类型的关键词。例如,声明一个整型变量,用Intvar numberOfYears: Int

Page 58 | Chapter3:Diving into Swift

最后,你必须给这个变量设定一个初始值,这个初始值必须符合你设定的类型,否则,这个变量就无法声明: var numberOfYears: Int = 30 这里的等号是用了初始化一个变量。初始化表示给变化一个默认值。把这个过程想象成打开一个新玩具,却忘记放电池,这个玩具没法玩直到我们把电池放进去。你必须初始化你的变量,赋一个默认值,不然这个变量无法使用。

整型(Integers)

整型,整数的正值或者负值,用Int表示。下面这行代码,用var表示这是一个变量,用favoriteNubmer作为变量名,紧接着用一个冒号来声明这个变量的类型。这行代码显示,这个变量的类型是整型,所以使用Int。最后,这个变量的初始值设定为4,跟在等号的后面: var favoriteNumber: Int = 4

浮点型(Float)

浮点型是指有小数点位的数值,用Float表示。例如,下面这行代码,用var表示这是一个变量,用accountBalance作为变量名,冒号声明这个变量是Float类型,最后,用等号表示这个变量的初始值是1203.51: var accountBalance: Float = 1203.51

布尔型(Boolean)

布尔型的值,只有true真或者false假,两种情况,用Bool表示。例如,下面这行代码,用var表示这是一个变量,用isStudent作为变量名,冒号后声明这个变量是Bool类型,最后,用等号表示这个变量的初始值是true: var isStudent: Bool = true

字符串类型(Strings)

字符串类型是指字符,英文的字母单词或者中文的汉字词汇等字符,要用双引号将字符串包含起来,用String表示。例如,下面这行代码,用var表示这是一个变量,用firstName作为变量名,冒号后声明这个变量是String类型,最后,用等号表示这个变量的初始值是Steve: var firstName: String = "Steve"

Creating Variables | Page59

记住任何时候声明变量时,都要遵循下面这个格式:var variableName: type = newValueHere

对象(Objects)

变量也可以表示对象,对象的类型就是类的名字。记住,类就是这个对象的蓝图,类里面包含了对象所有的属性和行为。 下面这行代码,用var表示这是一个变量,用fastCar作为变量名,冒号后声明这个变量是对象类型,在这里,就是Car,最后,用等号表示这个变量的初始值是一个新的车对象: var fastCar: Car = Car()

个人挑战:在Playground中声明你自己的整型、浮点型、布尔型和字符串类型的变量

常量(Constants)

有时候有些东西你确定它们是百分之百不会改变,比如你的生日。这时候,你可以用常量来代替变量。常量是用来处理那些不会改变的数值,一旦设定值后,在它的整个生命周期内,值都就不会再改变了。常量的值是静态的,静态意味着值在现在或者将来都不会改变。 定义一个常量和定义一个变量非常相似,唯一的区别是定义常量使用let而定义变量使用var。例如:

var numberOfYears: Int = 30`
let name: String = "Steve"
let isMale: Bool = true
var bankAccountBalance: Float = 1034.20

你会注意到name和isMale是常量,这些常量的值是永远不会改变的。 你也许会问:“为什么我不直接把所有的常量都用变量表示,然后一直不改变变量的值,这个也和常量没有什么区别了啊?” 恩,这样也是可行的,只是这个方法违背了编程的最佳实践原则。最佳实践原则能够为开发者和用户提供更好的体验。例如,使用一个常量代替变量能够节省内存和电量,如果所有的开发者都践行最佳实践原则,这样会给用户提供更好的体验。

个人挑战:在Playground中给你自己这个人来制作变量和常量,看看你能想到多少变量和常量来描述自己?

Page 60 | Chapter3:Diving into Swift

类型推断(Type Inference)

为每一个变量和常量声明类型可是一件体力活,苹果公司的工程师一直致力于让开发者的工作更轻松。基于你提供的等号右边的值,Swift可以自己判断类型,也就是具有类型推断的能力,这使得声明变量更加容易。请见下面的例子:

var numberOfYears = 30
let name = "Steve"
let isMale = true
var bankAccountBalance = 1034.20

冒号和冒号后面的类型就不需要了,因为Swift可以根据等号右边的值来推断类型,然后自动设定变量的类型。这样能节省不少时间,也能让代码更简洁。

修改字符串(Modifying Strings)

Swift中的字符串类(String class)提供了不少简便快捷的方法,例如uppercaseString,可以使小写字母改变为大写字母。//后面展示的是改变后的字符串效果。

var favoriteFood: String = "Pasta"
favoriteFood = favoriteFood.uppercaseString    //PASTA

当你设定favoriteFood变成favoriteFood.uppercaseString时,等号表明等号右边的值赋值给等号左边的变量,把这个过程拆解开来就是:

 1. favoriteFood  //"Pasta"
    2. favoriteFood.uppercaseString  //"PASTA"
    3. favoriteFood = favoriteFood.uppercaseString   //"PASTA"
    4. favoriteFood   //"PASTA"

Modifying Strings | Page61

大部分的代码会按顺序执行,第一行代码运行完毕后,编译器会运行第二行代码,接着第三行代码,依次进行。第一行代码在没有执行完毕之前,第二行代码是不会执行的。

个人挑战:如果你把上面的第三行从Playground中去掉,会发生什么?原因是?

当然,也有lowercaseString方法,把所有的字母都变成小写字母,还有capitalizedString方法,把所有的单词的首字母大写。

附加字符串(Appending Strings)

你可以在一个字符串变量的后面加上一串字符,也就是附加(appending):

var beach = "Beach"
beach = beach + "Ball"       //"BeachBall"

一个字符串可以和另一个字符串相加,组成一个新的字符串。例如:

let firstName = "Steve"
var lastName = "Derico"
lastName = firstName + lastName    //"SteveDerico"

还可以,在两个字符串之间附加一个字符串。例如:

let firstName = "Steve"
let lastName = "Derico"
var fullName = firstName + " " + lastName
var favoriteMovie = " Back to The Future"
var movieString = " My name is " + fullName + "  and my favorite movie is " + favoriteMovie    //My name is Steve Derico and my favorite movie is Back To The Future

字符串中的变量(Variables in Strings)

使用字符串插入(string interpolation),可以直接在变量中增加字符串。字符串插入这个术语是指在一个字符串里使用占位符来产生一个字符串。程序运行后,这些占位符就会直接调用。在这里,字符串是用双引号表示的,那么占位符是用\()表示的,两个括号中是需要插入的字符串。字符串插入这个方法可以将一个非字符串的变量方便地转换为字符串类型:

let seatsPerRow = 25
let numberOfRows = 25
var seatsString = "In the theater, there are \(numberOfRows) rows and \(seatsPerRow) seats in each row."   //In the theater, there are 15 rows and 25 seats in each other row.

Page 62 | Chapter3:Diving into Swift

集合(Collection)

在某些情况下,有必要将许多变量或常量更好地组织在一起,Swift提供2种集合类型来保存和组织这些变量。

数组(Arrays)

假设你想存储过山车中站在排的人的名字,你该怎么做?你可以为在一排中的每一个人声明一个变量,不过这样就会有些麻烦,你也不知道在某个时刻有多少人是在一排上。为了解决这种麻烦,我们用到了数组。 数组(Array)是按照聚体顺序存储多个变量的容器。数组可以存储几乎无限的元素(item),同时每个元素都有一个数组下标,准确标明此元素在数组中的位置。可以这样声明一个数组:

 var names: [ String ] = [ "Steve", "Jeff", "Andy", "Andrew", "Cole", "Mike", "Mikey" ]

开头还是var,接着是冒号,然后是方括号,方括号里是数组的类型,等号的右边,用方括号括起来所有的数组元素,里面每个数组元素用逗号分开。 在Swift中,数组中所有的元素必须是同样的类型,这以为着一个数组能存储所有的字符串,如上面的例子,但是不能存储整型和字符串2种不同的类型的元素。数组只能存储同样类型的变量。 对于一个既定的数组,Swift可以自行判断出类型,没有必要专门写出数组的类型,所以上面的数组也可以写成这样:

var names = [ "Steve", "Jeff", "Andy" ]

Collections | Page63

查找数组(Navigating arrays)

(Navigating arrays是查找数组的意思吗?导航数组?) 数组中的每个元素都有特定的位置或者下标,下标是从0开始的,第一个元素的下标是0,第二个元素的下标是1,第三个元素的下标是2,依此类推。获取数组中的某个元素使用下面的格式:

names[0]    // Steve
names[1]    //Jeff
names[2]    //"Andy

一开始可能不习惯零开头,时间长了,就会下意识的认为是以零开头了。下标都是以零开头的。

个人挑战:声明一个数组,来记录你的家庭成员

使用count方法可以获得数组中所有元素的总数。最后一个元素的下标会比总数少了一:

names.count         // 3

检查数组元素是否为空,这个数组中是否有元素,使用isEmpty方法:

var cats = [ "Big Kitty" ]
cats.isEmpty        //false

修改数组(Modifying arrays)

用var声明的数组是动态的可以按照需要改变,在数组最后一个元素后面附加一个元素使用append方法:

var names = [ "Steve", "Jeff", "Andy" ] 
names.append ( "Wally" )         //  [ "Steve", "Jeff", "Andy", "Wally" ]

也可以给你的数组增加一个数组:

Page 64 | Chapter3:Diving into Swift

var names = [ "Steve", "Jeff", "Andy", "Wally" ] 
var parents = [ "Mike", "Adam", "Nick" ]
names = names + parents           // [ "Steve", "Jeff", "Andy", "Wally", "Mike", "Adam", "Nick" ]

可以通过某个元素的下标来替换元素值,给这个元素赋新的值: names[6] = "Sam" 还有一个insert方法,可以在某个具体位置插入元素。插入元素后,此元素后面的元素的下标值都会自动增加1。

var names =  [ "Steve", "Jeff", "Andy", "Wally", "Mike", "Adam", "Sam" ]
names.insert ( "Buster", atIndex: 2 )      // [ "Steve", "Jeff", "Buster", "Andy", "Wally", "Mike", "Adam", "Sam" ]

而删减某个元素,使用removeAtIndex方法:

var names = [ "Steve", "Jeff", "Buster", "Andy", "Wally", "Mike", "Adam", "Sam" ]
names.removeAtIndex(2)       // [ "Steve", "Jeff", "Andy", "Wally", "Mike", "Adam", "Sam" ]

词典(Dictionaries)

数组不是唯一的集合类型,词典也可以存储多个变量,用键(Key)和值(value)将多个变量组织在一起。键值的工作原理和你书架上的牛津大词典类似,键(Key)是你要查找的单词,而值(value)是这个单词的释义。词典是无序存储的,所以只能使用键(key)来获取某个值(value),例如: var homeruns : [ String : Int ] = [ "Posey" : 24, "Pagan" : 19, "Pence" : 15 ] 在这个例子中,有三个键(keys):"Posey" , "Pagan" , "Pence",每个键都有对应的值。提高相关的键,写在中括号中,就能获取相对应的值: homeruns[ "Posey" ] // 24 增加一对键值:

var homeruns : [ String : Int ] = [ "Posey" : 24, "Pagan" : 19, "Pence" : 15 ]
homeruns[ "Sandoval" ] = 10    // [ "Posey" : 24, "Pagan" : 19, "Pence" : 15, "Sandoval" : 10 ]

Collections | Page65

给键设定一个新值就可以改变词典中的元素:

homeruns [ "Posey" ] = 36        //  [ "Posey" : 36, "Pagan" : 19, "Pence" : 15, "Sandoval" : 10 ]

将键对应的值设置为空(nil),就可以删除这对键值。nil是空值,我们将在章节结束的时候更深入的介绍nil。删除键值方法:

homeruns [ "Sandoval" ] = nil     //   [ "Posey" : 36, "Pagan" : 19, "Pence" : 15 ]

循环(Loops)

想象一下你在健身馆运动,你的健身教练告诉你要举重8次,同样的举重动作你要进行8次。编程中处理重复工作使用循环(Loops)。循环用来重复某段特定代码。

For条件递增语句(For-Condition-Increment)

最常见的循环就是For条件递增语句,简称for loop(for循环体)。这个循环有三部分构成:一个变量,一个条件,一个递增。这里的变量常常使用整型,来跟踪目前的已经完成的循环次数。这里的条件会在每次循环结束之后都会检查一次,如果条件结果为真,循环继续,如果条件为假,循环停止。最后,这里的递增是每次循环执行后需要增加的数值:

 for ( var counter = 0; counter < 8; counter++ )  {
         liftWeights( )
 }

语法是这样的:用for作为循环的开始,告诉Xcode你要声明一个循环了,for后面跟着括号,货号里面声明变量、条件和递增数值。例如:

for ( VARIABLE; CONDITION; INCREMENT )  {

}

括号中的第一个部分是变量,用counter表示,计算已经完成的循环的数量,在平时编写程序时,这里的变量常常命名为counter(英文中counter有计数器的含义)然后设定初始值为零:

for ( var counter = 0; CONDITION; INCREMENT )  {

}

Page 66 | Chapter3:Diving into Swift

接下来,在变量后面使用分号和条件分隔开来。在这个例子中,条件设定为counter小于8,这将会使循环执行8次。例如:

for ( var counter = 0; counter < 8; INCREMENT )  {

}

条件后面的一个分号后面是递增值,递增值就是每次循环后变量counter的变化:

for ( var counter = 0; counter < 8; counter++ )  {

}

大部分的递增值用两个加号这种简写方式。平时要给一个变量加1,语法一般是这样的: counter = counter + 1 这行代码表示变量counter加上1的值覆盖counter作为counter的新值,在执行for循环时,counter每次加1。然而苹果公司提供了简写方式,用两个加号++表示这个变量加1,例如: counter++ 作用和这个相同: counter = counter +1

for-in循环

每次写循环语句都要写变量、条件和增值,这可是一件费时费力的体力活。而for-in循环提供了一种更简单的方法去遍历(循环访问)一个数组或者词典。for-in循环可以自动的检测条件和递增值。此外,还会提供一个变量来表示目前数组中的元素。例如:

var favoriteStates = ["California", "New York", "Colorado", "Oregon"]
  for state in favoriteStates {
      println ( "\(state) is one of my favorite states" )
 }
//California is one of my favorite states
//New York is one of my favorite states
//Colorado is one of my favorite states
//Oregon is one of my favorite states

println方法,发音为"print line",能够生成字符串内容然后将内容展示在Debugger中(也就是常说的“打印”)。Debugger会在第六章中介绍。

Loops | Page67

for-in循环同样也可以在词典中使用,遍历词典中所有的键值,不过需要为键值设置2个变量:

var homeruns = [ "Posey" : 24, "Pagan" : 19, "Pence" : 15 ]
for (name, hrs) in homeruns {
     println( " \(name) has \(hrs) Homeruns this season.")
}
//Posey has 24 Homeruns this season. 
//Pagan has 19 Homeruns this season. 
//Pence has 15 Homeruns this season.

区间(Ranges)

区间Range和整型数组中一个数字到另一个数字差不多,目前有两种区间,一种是闭区间,用三个小点表示,包含小点两边的数字:

1...5   //1,2,3,4,5

另外一种是半闭半开区间,用两个小点加上一个小于号表示,小于号右边的数字不包含在这个区间中:

1..<5     //1,2,3,4

在for-in循环中,可以使用区间来代替数组或者词典:

for index in 1...5 {
    println ("The current number is \(index)")
}
 //The current number is 1 
 //The current number is 2 
 //The current number is 3 
 //The current number is 4 
 //The current number is 5

条件表达式(Conditional Statements)

你是否在餐馆遇到过会给过生日的人唱歌的情景?这就是一个条件表达式,在程序中,条件表达式是用来做决定的。

Page 68 | Chapter3:Diving into Swift

if表达式(if Statements)

类似这种做决定的情况或者可以判断是和否的逻辑问题,都可以使用条件表达式。if表达式决定一个情况为真或者为假,如果条件为真,某段代码就会执行,如果为假,则这段代码不会执行。例如:

if isBirthdayToday == true {
    singBirthdaySong ( )
}

条件表达式以if开头,然后跟着条件,在上面的这个例子中,条件是isBirthdayToday == true,两个等号表示比较2个等号之间的数值,如果值相同,则结果为真,如果值不相同,则结果为假。如果为真,就会执行singBirthdaySong ( )这个方法,如果为假,就会不执行singBirthdaySong ( )这个方法。最后,两个大括号表示这段代码的开始和结尾。

if-else表达式

在歌剧结束后,按惯例演员会出来谢幕,性别不同会有不同的动作,要么鞠躬,要么行屈膝礼。如果你想在Swift中表达这件事,可以这样写:

if isMale == true {
    bow()
} else {
    curtsy()
}

在这里例子中,我们需要看isMale是否为真,如果为真,bow()将会执行,如果为假,curtsy()将会执行,上面和下面两部分是相互排斥的,换句话说,你只能执行其中一个,要么上面,要么下面。 有时候你需要检查多个情况才能决定下一步做什么。比如你早上起床后,在工作日会有一套例行事宜,而在周末就会有另外一套例行事宜:

if isWeekday == true {
    getReadyForWork()
} else if isSaturday == true {
    goRunning()
} else {
    goToYoga()
}

Conditional Statements | Page69

在这个例子中,你首先要检查今天是不是工作日,如果今天是工作日,就要执行getReadyForWork(),然后跳过if语句中剩下的代码。如果今天不是工作日,就要跳过第一部分然后进入else if条件。 如果第一个条件为假,else if会被调用。如果今天是周六,goRunning()代码执行,然后跳过剩下的代码。 最后,如果上面两个条件都为假,那么else就会被调用。如果今天既不是工作日也不是周六,那么 goToYoga()会执行。 在日常的编程中,if条件句是非常有力的工具,经常使用if来控制逻辑。记住,要检查每个条件,确保结果只有真或假两种情况。

可选类型(Optionals)

可选值是用来处理那些可能出现空值的变量。在某些情况下,你是无法确保一个变量是不是一定有值。例如,在西班牙语中的一个单词,可能无法直接翻译成英语的一个单词,这样就会出现空值。这种没有值的情况叫做nil。 可选值可以用在任何类型的变量中,在使用时将一个问号跟在类型后面,表示这是可选值: var translatedWord: String? 因为可能为空的变量都必须名称表示,这样能确保所有的非可选值变量都会有值。这种设计模式帮助开发者避免了空值引起的程序崩溃。非可选值变量都必须有值,可选值变量可以没有值。 可选值不能直接使用,在使用之前需要解包(unwrapped)。把使用可选值变量想象成拆开一袋糖果,必须先要把包装撕掉才能吃到糖果。当一个可选值变量解包后,这个变量也可能是空值。这就相当于你拆开一颗糖果,结果发现里面什么也没有。 解包的过程帮助开发者记住去检查然后确保这个变量不是空值,用可选值有2个步骤,第一步,检查是不是为空,一般情况下用if表达式检查:

var translatedWord: String? = translate("cat")
if translatedWord != nil {
       //translatedWord has a value
 } else {
     //The translatedWord has no value
 }

Page 70 | Chapter3:Diving into Swift

一旦核查确实有值后,你必须解包。解包一个可选值非常简单,直接放一个叹号在变量后面即可,例如:

var translatedWord: String? = translate("cat")
if translatedWord != nil {
    println(translatedWord!)    //gato
}

刚刚开始接触可选值的时候会有一些困惑和不习惯,其实你只要记住,一个可能为空的变量必须是可选值,而当可选值为空时就叫做nil。

在这一章节,你学会了Swift的基本知识,你现在能够声明变量、常量、甚至是可选值了。你熟悉了如何声明字符串,整型,浮点型,数组和词典,你也理解了如果声明一个循环体,一个条件语句。现在,是时候让你接受一下检测了,再接再励完成小费计算器程序吧~