简介
这是一个Swift语言教程,基于最新的iOS 9,Xcode 7.3和Swift 2.2,会为你介绍Swift编程非常基础的内容。从电脑如何工作的全程基本原理到语言结构,你会足够了解这门语言,来处理数据和管理代码的行为。
快速链接
- 一个下午让你掌握Swift基础 ( 1/9 ) 编程本质 & Playground基础
- 一个下午让你掌握Swift基础 ( 2/9 ) 变量 & 常量
- 一个下午让你掌握Swift基础 ( 3/9 ) 数字类型 & 操作
- 一个下午让你掌握Swift基础 ( 4/9 ) 字符串
- 一个下午让你掌握Swift基础 ( 5/9 ) 做判断
- 一个下午让你掌握Swift基础 ( 6/9 ) 重复步骤
- 一个下午让你掌握Swift基础 ( 7/9 ) 函数
- 一个下午让你掌握Swift基础 ( 8/9 ) 闭包
- 一个下午让你掌握Swift基础 ( 9/9 ) 可选值
- Swift 初学者 ( 10/12 ) 数组
- Swift 初学者 ( 11/12 ) 字典
- Swift 初学者 ( 12/12 ) 集合
做判断
写一个电脑程序的时候,需要能够用不同的剧本告诉电脑该干什么。例如,一个计算器app在用户按加号按钮的时候要做一件事,按减号按钮的时候做另一件事。
在电脑编程领域,这个概念被称作控制流(control flow)。它被这样命名因为程序的流程(flow)由多种方法控制。在这篇文章里,你会学习到在程序里如何做判断,以及通过使用语法来控制流程。
if语句
第一个也是最常用的控制程序流程的方式就是使用if语句(if statement),可以让程序只在某个特定情况是true的时候做一些事。例如,看下面的代码:
if 2 > 1 {
print("是的,2比1大。")
}
这一个简单的if语句。如果括号里的情况是true,语句就会执行花括号里的代码。如果括号里的情况是false,语句不会执行花括号里的代码。就这么简单!
上面的代码也为你介绍了新语法:print()函数,简单地显示一些东西到屏幕上。在你的playground里,你可以看见上面print()语句的结果,通过点击 View\Debug Area\Show Debug Area。
你会看见这样的东西:
点击上面截图上高亮的两个按钮也可以显示debug(排除错误)区域。Xcode有很多方式来完成同样的事情!
你可以扩展一个if语句,提供在情况是false的时候运行的代码。这被称作else子句(clause)。这是一个例子:
let animal = "狐狸"
if animal == "猫" || animal == "狗" {
print("这个动物是居家宠物。")
} else {
print("这个动物不是居家宠物。")
}
这里,如果(if)animal等于“猫”或“狗”,然后语句会运行代码的第一块。如果animal既不等于“猫”又不等于“狗”,语句会运行if语句里else里的那部分代码,在debug区域显示如下内容:
这个动物不是居家宠物。
其实使用 if 语句还能做更多事情。有时候你想检测一个情况,然后是另一个情况。这就是else-if语句参演的地方啦。
你可以像这样使用:
let hourOfDay = 12
let timeOfDay: String
if hourOfDay < 6 {
timeOfDay = "清晨"
} else if hourOfDay < 12 {
timeOfDay = "上午"
} else if hourOfDay < 17 {
timeOfDay = "下午"
} else if hourOfDay < 20 {
timeOfDay = "晚上"
} else if hourOfDay < 24 {
timeOfDay = "夜深了"
} else {
timeOfDay = "这他妈不是时间!"
}
print(timeOfDay)
一个接一个的else-if语句来测试多种情况,直到发现一个true情况。它只会执行和第一个true情况相关的代码,无论随后的else-if情况是不是true。换句话说,else-if情况的顺序影响很大!
你可以在末尾加一个else,来处理所有都不是true的情况。else是可选的,如果你不需要它那就不要;在这个例子里你的确需要它,来确保timeOfDay在你输出它的时候有一个有效值。
这个例子里,else-if语句带有一个数字,表示一天中的时间,然后把它转换到一个字符串,表示这个小时属于一天中的哪个部分。采用24小时时间制,语句被按顺序一个一个检查:
- 第一次检查看看小时是不是小于6。如果是,意味着在清晨。
- 如果小时不小于6,语句继续执行第一个else-if,检查小时是不是小于12。
- 然后按顺序,在情况是false的时候,语句检查小时是不是小于17,然后是小于20,然后是小于24。
- 最后,如果小时数超出范围了,语句察觉到了一个无效情况,然后把这个信息打印到了控制台。
在上面的代码里,hourOfDay常量是12。因此,代码会在屏幕上像下面这样显示:
下午
注意即使hourOfDay < 20和hourOfDay < 24情况也都是true,但语句只执行了输入满足的第一个else-if,当然就是hourOfDay < 17情况啦。
包含变量
If 语句介绍了一个新概念,那就是scope(范围),通过使用花括号来包含变量的一种方式。
让我们看一个例子。想象一下你要计算向顾客收取的费用。
这是你打好的算盘:
你每小时赚25块,最多40小时,此后的每小时都要50块。
使用Swift,你可以这样计算你的费用:
var hoursWorked = 45
var price = 0
if hoursWorked > 40 {
let hoursOver40 = hoursWorked - 40
price += hoursOver40 * 50
hoursWorked -= hoursOver40
}
price += hoursWorked * 25
print(price)
这段代码检查小时数是不是超过40了。如果是,代码计算超过40的小时数,然后用它乘上50块,然后把结果加到价格上。代码然后从工作的总时间里减去超过40小时的部分。把剩下的工作小时乘以25块,然后加到总价上。
在上面的例子里,结果是这样的:
1250
有意思的是 if 语句里面的代码。有一个新常量的声明,hoursOver40,来保存超过40小时的数字。
很明显你可以在if语句里面使用它。但如果你尝试在上面代码的结尾去使用它,会发生什么?
···
print(price)
print(hoursOver40)
这会导致下面的错误:
`error: use of unresolved identifier 'hoursOver40'(错误:使用了不确定的标识符‘hoursOver40’)`
这个错误告诉你,你只被允许在创建 hoursOver40 常量的 scope 里使用它。这个例子里,if 语句引入了一个新 scope,所以当这个 scope 结束了,你就不能再使用这个常量了。
但是,每个 scope 可以使用来自它的父 scope 的变量和常量。在上面的例子里,if 语句里面的scope使用了 price 和 hoursWorked 变量,他们就是在父 scope 被创建的。
三目操作符(The ternary conditional operator)
现在我想介绍一个新的操作符,你在第三篇文章里没有看到的。叫做三目操作符(The ternary conditional operator),它是和 if 语句相关的。
如果你想判断两个变量最小的值和最小的值,你可以像这样使用if语句:
let a = 5
let b = 10
let min: Int
if a < b {
min = a
} else {
min = b
}
let max: Int
if a > b {
max = a
} else {
max = b
}
现在你知道这是怎么工作的了,但这有好多代码。如果你能把它缩短到就几行岂不是很好?唔,你可以的,感谢三目操作符!
三目操作符带有一个情况,返回两个值其中之一,取决于那个情况是true还是false。语法如下所示:
(<情况>) ? <TRUE值> : <FALSE值>
你可以使用这个操作符来重写上面的长代码块,像这样:
let a = 5
let b = 10
let min = a < b ? a : b
let max = a > b ? a : b
第一个例子里,情况是a<b。如果是true,赋值回min的结果会是a;如果是false,结果会是b的值。
我相信你也同意这样简单多了!这是一个有用的操作符,你会发现自己经常使用它。
**注意:**因为找两个数字中更大的或更小的那个是如此常用的操作,Swift标准库为这个目标提供了两个函数:max和min。
迷你练习
创建一个叫做myAge的常量,初始化为你的年龄。写一个if语句,如果你的年龄在13到19之间,就print“青少年”,如果不是,就print“不是青少年”。
Swift语句
控制流程的另一种方式是使用 switch 语句,允许你根据变量或常量的值来执行不同的代码。
这是一个非常简单的基于整数的 switch 语句:
let number = 10
switch (number) {
case 0:
print("零")
default:
print("非零")
}
这个例子,代码会如下输出:
非零
这个switch语句的作用是判断数字是不是零。但它可以做更复杂一点的事!
要处理一个特殊情况,使用 case 后面跟着你想判断的值,这个例子里是0。然后,用default来表明,如果是所有其它值应该做点什么。
这是另一个例子:
let number = 10
switch (number) {
case 10:
print("这是10!")
default:
break
}
这次你判断10,在case里print了一条消息。如果是其他值,那什么都不应该发生。当你不想让一个case或default发生任何事情的时候,那就用break关键字。这告诉Swift你不打算在这里写任何代码,任何事都不应该发生。
当然,switch语句也可以处理整数以外的数据类型。他们可以处理任何数据类型!这是一个基于string的例子:
let string = "狗"
switch (string) {
case "猫", "狗":
print("这个动物是居家型。")
default:
print("这个动物不是居家型。")
}
这会print如下内容:
这个动物是居家型。
这个例子里,你为case提供了两个值,意味着如果值等于“猫”或“狗”,语句就会执行这个case。
你也可以给switch语句不止一个case。你在这篇文章之前的部分看见了一个 if 语句带有 else-if 从句,可以把一天中的小时转换为描述这是一天中的哪个部分的字符串。你可以用一个switch语句来更简要的重写它,像这样:
let hourOfDay = 12
let timeOfDay: String
switch (hourOfDay) {
case 0, 1, 2, 3, 4, 5:
timeOfDay = "清晨"
case 6, 7, 8, 9, 10, 11:
timeOfDay = "上午"
case 12, 13, 14, 15, 16:
timeOfDay = "下午"
case 17, 18, 19:
timeOfDay = "晚上"
case 20, 21, 22, 23:
timeOfDay = "夜深了"
default:
timeOfDay = "这他妈不是时间!"
}
print(timeOfDay)
代码会 print 如下内容:
下午
如果有多个case,语句会执行第一个满足的case。你应该会同意这个例子比用if语句来的更简要和清晰吧。细节上其实也更严谨,因为 if 语句没法处理负数的情况,但这儿负数被正确地认为是无效的。
基于一个值的property来匹配一个case的情况也是可以的。就像你在第三篇学的,你可以使用模除操作符来判断一个整数是偶数还是奇数。看看这段代码:
let number = 10
switch (number) {
case let x where x % 2 == 0:
print("偶数")
default:
print("奇数")
}
这会print如下内容:
偶数
这个switch语句使用了let-where语法,意味着case只会在一个特定情况是true的时候匹配。这个例子里,你设计了case来满足如果值是偶数的情况——那就是值模除2等于0啦。
这个可以基于情况来匹配值的方法叫做模式匹配(pattern matching)。
另一种方式使用switch语句也有绝佳效果,像这样:
let coordinates: (x: Int, y: Int, z: Int) = (3, 2, 5)
switch (coordinates) {
case (0, 0, 0): // 1
print("原点")
case (_, 0, 0): // 2
print("在x轴上。")
case (0, _, 0): // 3
print("在y轴上。")
case (0, 0, _): // 4
print("在z轴上。")
default: // 5
print("空间里的某个位置")
}
这个switch语句利用了部分匹配(partial matching)。按顺序说一下每个case都做了什么:
- 恰好匹配值是(0, 0, 0)的情况。这是3D空间的原点。
- 匹配y=0, z=0以及任意的x值。这意味着坐标点在x轴上。
- 匹配x=0, z=0以及任意的y值。这意味着坐标点在y轴上。
- 匹配x=0, y=0以及任意的z值。这意味着坐标点在z轴上。
- 匹配剩下的坐标。
用下划线来表示你不在乎这个值。你早在第二篇文章就见过了,会并会在贯穿教程的多个地方看见它。因为这太好用了!
如果你不想忽略值,那你就能在switch语句里使用它,像这样:
let coordinates: (x: Int, y: Int, z: Int) = (3, 2, 5)
switch (coordinates) {
case (0, 0, 0):
print("原点")
case (let x, 0, 0):
print("在x轴上 x = \(x)")
case (0, let y, 0):
print("在y轴上 y = \(y)")
case (0, 0, let z):
print("在z轴上 z = \(z)")
case (let x, let y, let z):
print("空间里的某个位置 x = \(x), y = \(y), z = \(z)")
}
这里坐标轴 case 使用 let 语法来把有关值取出。代码然后使用字符串插入来构建一个字符串,把它 print 出来。
注意为什么这个switch语句不需要一个default。这是因为最后的case本质上就是default—它匹配任何值,因为对元组的任一部分都没有限制。如果switch语句在cases里用光了所有可能的值,那就不需要什么default了。
最后,你也可以用与之前看到的同样的let-where语法来匹配更复杂的情况。例如:
let coordinates: (x: Int, y: Int, z: Int) = (3, 2, 5)
switch (coordinates) {
case (let x, let y, _) where y == x:
print("在y = x线上。")
case (let x, let y, _) where y == x * x:
print("在y = x^2线上。")
default:
break
}
这里,你匹配了“y等于x”和“y等于x的平方”两条线。
这些就是switch语句的基础啦!
迷你练习
- 写一个switch语句,基于一个整数的年龄,然后print出这个年龄对应的年龄层。你可以自己做一个年龄层,或者用我的分类方法:0-2岁:幼儿,3-12岁:儿童,13-19岁:青少年,20-39岁:成年人,40-60:中年人;61+:老人。
- 写一个switch语句,基于包含了一个字符串和一个整数的元组。字符串是一个名字,整数是一个年龄。用和你在前一个练习同样的情况,用 let 语法来 print 出名字接着年龄层。例如,我自己就应该 print 出“张嘉夫是一个成年人。”
关键点
- 用 if 语句做基于一个情况的简单判断。
- 在 if 语句里用 else 和 else-if 来为做判断扩展,不止一个单独的情况。
- 你可以在简单 if 语句的地方用三目操作符。
- 变量和常量属于一个特定的scope(范围),越过了scope就不能再用他们了。一个scope可以继承父scope的变量和常量。
- 用 switch 语句来基于一个变量或常量的值决定运行哪段代码。
- switch 语句的强大来自于它使用模式匹配的能力,因为值可以用复杂规则来进行比较。
接下来去哪儿?
Apps很少全程时刻都运行在同样的方式;根据来自网络或用户输入的内容,你的代码需要做判断去哪条路。有了if,else和switch语句,你可以让代码基于一些情况来做决定。
和决定是否要做一些事相似,你也能决定做一些事多少次。在下一篇文章里,你会看到如何使用循环来多次重复步骤。
挑战
挑战A:你就是编译器
下面的代码哪里错了?
let firstName = "嘉夫"
if firstName == "嘉夫" {
let lastName = "张"
} else if firstName == "阳" {
let lastName = "刘"
}
let fullName = lastName + firstName
挑战B:结果预测
看看下面的switch语句:
switch (coordinates) {
case (let x, let y, let z) where x == y && y == z:
print("x = y = z")
case (_, _, 0):
print("在x/y平面上")
case (_, 0, _):
print("在x/z片面上")
case (0, _, _):
print("在y/z平面上")
default:
print("没什么特别的")
}
在coordinates分别是下列每一个的时候,代码会 print 什么?
let coordinates = (1, 5, 0)
let coordinates = (2, 2, 2)
let coordinates = (3, 0, 1)
let coordinates = (3, 2, 5)
let coordinates = (0, 2, 4)
介绍
欢迎来到Swift世界!Swift是一门苹果在2014年夏天发布的编程语言。从那之后,Swift发布了一个主要的版本跳跃,成为了开始在苹果平台:iOS,OS X,watchOS和tvOS开发的最简单的方式。
谁适合这篇教程
这篇教程适合懂一点编程、并且希望学习Swift的人。也许你已经为网站写过一些JavaScript代码,或者用Python写过一些简短的程序。这篇教程就是为你准备的!你会学习到编程的基本概念,同时也会成为Swift语言小能手。
如果你是赤裸裸的编程新手,这篇教程也是为你准备的!教程里贯穿有简短的锻炼和挑战来给你一些编程练习,同时测试你的知识。
需要准备什么
要看这篇教程,你需要准备如下的东西:
- 一台运行OS X El Captian(10.11)的Mac,带有最新发布的更新并且安装了安全补丁。这样你才能够安装需要的开发工具:最新版本的Xcode。
- Xcode 7.3 或更新的版本。Xcode是用Swift写代码的主要开发工具。最小也需要Xcode 7.3版本,因为那个版本包含Swift 2.2。你可以免费从Mac App Store下载Xcode的最新版本,这里:http://apple.co/1FLn51R。
如果你还没有安装Xcode最新版本,在继续看下面的教程前要确定安装。
如何使用这篇教程
每篇教程都会介绍触手可及的话题理论,伴随大量Swift代码来示范在学习的实际的应用程序。
教程里的所有代码都是平台中立的;这意味着不是为iOS、OS X或任何其它平台而特定。代码在playgrounds里运行,你在本篇中已经学习了。
在剩下的教程里,你可以把代码在自己的playground里输入进去。这样你就可以和代码“玩耍”(play around),做一些改变立即就能看见代码运行的结果。
剩下的教程里会贯穿实际小练习,都是简短的练习,关于触手可及的主题。每篇的末尾也有挑战,会有编程问题也会有长一点的代码练习来测试你的知识。做完就能掌握大部分的Swift基础知识。
教程更新
教程会随Swift语言的更新而更新,会发布在我的简书和知乎专栏上,搜索“张嘉夫”即可关注我。
目录
本教程从一些基础工作开始来让你起步:
- 第1篇,编程本质 & Playground基础 - 这就是,到编程世界的入门介绍!你会从电脑和编程的预览开始,然后剩余时间给Swift playground打个招呼。
- 第2篇,变量 & 常量 - 你会学习到变量和常量,这是用来存储数据的“地方”。你也会学习数据类型以及Swift如何追踪数据类型并在代码中进行传输。
- 第3篇,数字类型 & 操作 - 你会从基础的数字类型比如整形和浮点型数字开始,当然也包括布尔类型。也会看到一些在实际操作,从比较到算数操作如加减。
- 第4篇,字符串 - 用字符串来存储文字-从按钮里的文字到图片的标注到这篇教程全部的文字,存储这所有的一切!你会学习到string和character类型,以及基于这些类型的一些常见操作。
在脑海中有基础数据类型后,就该用那些数据做一些事情了:
- 第5篇,做判断 - 代码不总是直接从头运行到尾。你会学习在代码里如何做判决并且设定情况来运行某段代码。
- 第6篇,重复步骤 - 继续不要让代码直线运行的主题,你会学习到如何使用循环来重复某些步骤。
- 第7篇,函数 - 函数是Swift中用来构建代码的基础建筑。你会学习到如何定义函数来分组代码到可复用单元中。
- 第8篇,闭包(Closures) - 闭包和函数很接近。你会学习到如何使用它们来轻松传递代码块。
最后一篇会回到数据:
- 第9节,可选值 - 这篇讲可选值,Swift中的一种特殊类型,表示既有可能是一个真实的值也有可能没有值。这篇的最后你会知道为什么要用可选值以及如何安全地使用它们。
这些基础会让你快速开始Swift之路,做好接触更高级编程主题的准备。