Swift简介
在学习Swift之前,我们先来了解下什么是Swift
Swift是Apple
在2014年6月WWDC
发布的全新编程语言,中文名和LOGO是”雨燕“
Swift之父是Chris Lattner
,也是Clang
编译器的作者,LLVM
项目的主要发起人
Swift版本
Swift历时七年,从Swift 1.*
更新到Swift 5.*
,经历了多次重大改变,ABI
终于稳定
API(Application Programming Interface):应用程序编程接口
ABI(Application Binary Interface):应用程序二进制接口
- 应用程序和操作系统之间的底层接口
- 涉及的内容有:目标文件格式、数据类型的大小/布局/对齐,函数调用约定等
Swift是完全开源的,下载地址:https://github.com/apple/swift
Swift编译原理
LLVM编译器
LLVM编译器一般分为前端和后端
- 前端:主要进行词法分析,生成语法树
- 后端:生成对应平台的二进制代码
编译流程
我们知道OC的前端是通过Clang
进行编译的,Swift的前端是通过swiftc
来编译的
不同语言的前端可能不同,但最终都会通过编译器的后端生成对应平台的二进制代码

整个编译流程如下图所示

- Swift Code:我们编写的Swift代码
- Swift AST:Swift语法树
- Raw Swift IL:Swift特有的中间代码
- Canonical Swift IL:更简洁的Swift特有的中间代码
- LLVM IR:LLVM的中间代码
- Assembly:汇编代码
- Executable:二进制代码
关于Swift编译流程的详细讲解可以参考以下网址:https://swift.org/swift-compiler/#compiler-architecture
swiftc
我们打开终端,输入swiftc -help
,会打印出相关指令,这也说明了swiftc
已经存在于Xcode中

我们可以在应用程序中找到Xcode
,然后右键显示包内容
,通过该路径找到swiftc
路径:/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin


swiftc的基本操作演练
下面我们可以通过一些swiftc
的一些基本操作来了解
1.我们先新建一个Swift的命令行项目


2.然后打开终端,cd
到main.swift
路径

3.然后我们输入swiftc -dump-ast main.swift
,来查看下生成的语法树

4.我们还可以输入swiftc -emit-sil main.swift
生成最简洁的SIL代码

5.我们还可以输入swiftc -emit-ir main.swift
生成LLVM IR中间代码

6.我们还可以输入swiftc -emit-assembly main.swift
生成汇编代码

Swift基础语法
Swift中打印输入:print("Hello World")
Swift中一句代码是可以省略分号的,但是如果多句代码写在一行,需要用分号隔开
常量和变量
常量:
1.用let
定义常量,常量只能赋值一次
不用特意指明类型,编译器会自动进行推断
let a: Int = 10
let b = 20
2.它的值不要求在编译过程中确定,但使用之前必须赋值一次
这样写确定了a的类型,之后再去赋值,也不会报错
let a: Int
a = 10
用函数给常量赋值也可以,函数是在运行时才会确定值的,所以只要保证使用之前赋值了就行
func getNumber() -> Int {
return 10
}
let a: Int
a = getNumber()
如果没有给a确定类型,也没有一开始定义的时候赋值,就会像下面这样报错

变量:
1.用var
定义变量
var b = 20
b = 30
2.常量、变量在初始化之前,都不能使用

注释
1.Swift中有单行注释和多行注释
注释之间嵌套也没有问题
// 单行注释
/*
多行注释
/*
多行注释
*/
/*
// 注释嵌套
*/
2.Playground
里的注释支持Markup
语法(同Markdown)
Markup
语法只在Playground
里有效,在项目中无效
//: # 一级标题
/*:
## 基础语法
*/
可以通过Editor -> Show Raw Markup
来预览

预览的效果如下

标识符
1.标识符(比如常量名、变量名、函数名)几乎可以使用任何字符
let ?? = 5
var ?? = 10
func ??() {
}
标识符不能以数字开头,不能包含空白字符、制表符、箭头等特殊字符

常见数据类型
常见类型
- 值类型
- 枚举(enum): Optional
- 结构体(struct): Bool、Double、Float、Int、Character、String、Array、Dictionary、Set
- 引用类型
可以通过command+control
进入到该类型的API中查看
例如Int类型

整数类型
整数类型:Int8、Int16、Int32、Int64、UInt8、UInt16、UInt32、UInt64
在32bit平台,Int等于Int32;在64bit平台,Int等于Int64
整数的最值:UInt8.max,Int16.min
一般情况下,都是直接使用Int即可
let a: Int8 = 5
浮点类型
Float:32位,精度只有6位
Double:64位,精度至少15位
浮点型不指明类型默认就是Double
let a: Float = 2.0
let b = 3.0
字面量
字面量就是指这个量本身,就是一个固定值的表示法
下面这些都是字面量
Bool布尔
一般用Bool
类型来表示是否的判断,是为true
,否为false
let bool = true
字符串、字符
字符串的写法
let string = "hello"
字符类型要写上Character
,否则会被认为是字符串
字符可存储ASCII字符、Unicode字符
let character: Character = "a"
整数
不同进制的表示法
- 二进制以
0b
开头
- 八进制以
0o
开头
- 十六进制以
0x
开头
let intDecimal = 17 // 十进制
let intBinary = 0b10001 // 二进制
let intOctal = 0o21 // 八进制
let intHexadecimal = 0x11 // 十六进制
浮点数
let doubleDecimal = 125.0 // 十进制
let doubleDecimal2 = 1.25e2 // 也是125.0的另一种写法,表示1.25乘以10的二次方
let doubleDecimal3 = 0.0125
let doubleDecimal4 = 1.25e-2 // 也是0.0125的另一种写法,表示1.25乘以10的负二次方
let doubleHexadecimal1 = 0xFp2 // 十六进制,意味着15*2^2(15乘以2的二次方),相当于十进制的60
let doubleHexadecimal2 = 0xFp-2 //十六进制,意味着15*2^-2(15乘以2的负二次方),相当于十进制的3.75
整数和浮点数可以添加额外的零或者下划线来增强可读性
let num = 10_0000
let price = 1_000.000_000_1
let decimal = 000123.456
数组
let array = [1, 2, 3, 4]
字典
let dictionary = ["age" : 18,
"height" : 1.75]
类型转换
整数转换
let int1: UInt16 = 2_000
let int2: UInt8 = 1
let int3 = int1 + UInt16(int2)
整数、浮点数转换
let int = 3
let double = 0.1415926
let pi = Double(int) + double
let intPi = Int(pi)
字面量可以直接相加,因为数字字面量本身没有明确的类型
let result = 3 + 0.14159
元组(tuple)
元组是可以多种数据类型组合在一起
let http404Error = (404, "Not Found")
print("The status code is \(http404Error.0)")
// 可以分别把元组里的两个值分别进行赋值
let (statusCode, statusMsg) = http404Error
print("The status code is \(statusCode)")
// 可以只给元组里的某一个值进行赋值
let (justTheStatusCode, _) = http404Error
// 可以在定义的时候给元组里面的值起名
let http200Status = (statusCode: 200, description: "ok")
print("The status code is \(http200Status.statusCode)")
流程控制
if-else
Swift里的if else
后面的条件是可以省略小括号的,但大括号不可以省略
let age = 10
if age >= 22 {
print("Get married")
} else if age >= 18 {
print("Being a adult")
} else if age >= 7 {
print("Go to school")
} else {
print("Just a child")
}
if else
后面的条件只能是Bool类型

while
var num = 5
while num > 0 {
print("num is \(num)")
// 打印了五次
}
repeat-while
相当于C语言中的do-while
先执行一次,再判断条件循环
var num = -1
repeat {
print("num is \(num)")
// 打印了一次
} while num > 0
这里不用num--
是因为Swift3
开始,已经去掉了自增(++)、自减(--)运算符
for
1.闭区间运算符:a...b
,相当于a <= 取值 <= b
// 第一种写法
let names = ["Anna", "Alex", "Brian", "Jack"]
for i in 0...3 {
print(names[i])
}
// 第二种写法
let range = 0...3
for i in range {
}
// 第三种写法
let a = 1
let b = 3
for i in a...b {
}
循环里的i
默认是let
,如需要更改加上var
for var i in 0...3 {
}
不需要值的时候用_
来表示
for _ in 0...3 {
}
2.半开区间运算符:a..<b
,相当于a <= 取值 < b
for i in 0..<3 {
}
3.单侧区间:让一个区间朝一个方向尽可能的远
for i in ...3 {
}
for _ in 3... {
}
4.区间运算符还可以用在数组上
let names = ["Anna", "Alex", "Brian", "Jack"]
for name in names[0...3] {
print(name)
}
for name in names[2...] {
print(name)
}
for name in names[...2] {
print(name)
}
for name in names[..<2] {
print(name)
}
let range = ...5
range.contains(4)
5.区间的几种类型
闭区间 ClosedRange<Int>
1...3
半开区间 Range<Int>
1..<3
单侧区间 PartialRangeThrough<Int>
...3
6.字符、字符串也能使用区间运算符,但默认不能用在for-in
中
let stringRange1 = "cc"..."ff"
stringRange1.contains("cd")
let stringRange2 = "a"..."f"
stringRange2.contains("c")
let characterRange:ClosedRange<Character> = "\0"..."~"
characterRange.contains("G")
7.带间隔的区间值
let hours = 10
let hourInterval = 2
// tickmark的取值,从4开始,累加2,不超过10
for tickmark in stride(from: 4, through: hours, by: hourInterval) {
print(tickmark)
// 4,6,8,10
}
switch
使用同C语言的switch
,不同的是case、default
后面不写大括号{}
var number = 1
switch number {
case 1:
print("number is 1")
break
case 2:
print("number is 2")
break
default:
print("number is other")
break
}
默认不写case
,并不会贯穿到后面的条件
var number = 1
switch number {
case 1:
print("number is 1")
case 2:
print("number is 2")
default:
print("number is other")
}
使用fallthrough
可以实现贯穿效果
var number = 1
switch number {
case 1:
print("number is 1")
fallthrough
case 2:
print("number is 2")
default:
print("number is other")
}
// 会同时打印number is 1,number is 2
switch
必须要保证能处理所有情况
注意:像判断number的值,要考虑到所有整数的条件,如果不要判断全部情况,加上default
就可以了

case、default
后面至少要有一条语句
如果不想做任何事,加个break
即可
var number = 1
switch number {
case 1:
print("number is 1")
case 2:
break
default:
break
}
如果能保证已处理所有情况,也可以不必使用default
enum Answer { case right, wrong }
let answer = Answer.right
switch answer {
case .right:
print("right")
case .wrong:
print("wrong")
}
switch
也支持Character
和String
类型
let string = "Jack"
switch string {
case "Jack":
fallthrough
case "Rose":
print(string)
default:
break
}
switch
可以同时判断多个条件
let string = "Jack"
switch string {
case "Jack", "Rose":
print(string)
default:
break
}
let character: Character = "a"
switch character {
case "a", "A":
print(character)
default:
break
}
switch
也支持区间匹配和元组匹配
let count = 62
switch count {
case 0:
print("none")
case 1..<5:
print("a few")
case 5..<12:
print("several")
case 12..<100:
print("dozens of")
default:
print("many")
}
可以使用下划线忽略某个值
let point = (1, 1)
switch point: {
case (2, 2):
print("1")
case (_, 0):
print("2")
case (-2...2, 0...):
print("3")
}
值绑定,必要时let
也可以改成var
let point = (2, 0)
switch point: {
case (let x, 0):
print(x)
case (0, let y):
print("2")
case let (x, y):
print("3")
}
where
一般where
用来结合条件语句进行过滤
let point = (1, -1)
switch point {
case let (x, y) where x == y:
print("on the line x == y")
case let (x, y) where x == -y:
print("on the line x == -y")
case let (x, y):
print("\(x), \(y) is just some arbitrary point")
}
for i in 0...5 where i == 3 {
print(i)
}
标签语句
用outer
来标识循环跳出的条件
outer: for i in 1...4 {
for k in 1...4 {
if k == 3 {
continue outer
}
if i == 3 {
break outer
}
}
}