大家好,我是Mars。更新了Xcode 11 正式版后,对 Swift UI 做了一些简单的尝试,功能很强大,需要更深入的研究。之前在工作中业余时间自学了Swift,尝试重构了我司线上项目。后来因为项目赶进度,对Swift的研究也就搁浅下来。Swift 5 发布以后, ABI更加稳定,苹果今年又推出了 Swift UI ,所以是时候好好研究一下 Swift 这门语言了。后续会通过一系列的文章来分享和总结学习 Swift 的整个过程,希望大家多多支持和关注。
语法篇
一、基础语法
分号
Swift不要求在每行语句的结尾使用分号;
,当在同一行书写多条语句时,必须用分号隔开:
var str = "Hello, swift"
print(str)
let name = "Mars"; let age = 18;
标识符
标识符就是给变量、常量、方法、函数、枚举、结构体、类、协议等指定的名字。构成标识符的字母均有一定的规范,Swift语言中标识符的命名规则如下:
- 区分大小写,
Myname
与myname
是两个不同的标识符; - 标识符首字符可以以下划线
_
或者字母开始,但不能是数字; - 标识符中其他字符可以是下划线
_
、字母或数字。
Swift中的字母采用的是 Unicode
编码。Unicode
叫做统一编码制,它包含了亚洲文字编码,如中文、日文、韩文等字符,甚至是我们在聊天工具中使用的表情符号
let = 20
var = "Chicken"
如果一定要使用关键字作为标识符,可以在关键字前后添加重音符号(`),例如:
let `class` = "asda"
Swift 空格
Swift语言并不像C/C++,Java那样完全忽视空格,Swift对空格的使用有一定的要求,但又不像Python对缩进的要求那么严格。
在Swift中,运算符不能直接跟在变量或常量的后面。例如下面的代码会报错:
let a= 1 + 2
let b = 1+ 2
只有这样写才不会报错:
let a = 1 + 2; // 编码规范推荐使用这种写法
let b = 3+4 // 这样也可以
打印输出
Swift 使用自带的 print
函数打印输出:
print("Mars") // 输出 Mars
print
函数是一个全局函数,完整的函数签名为:
/// - Parameters:
/// - items: 需要打印的参数
/// - separator: 分隔符,默认使用空格来做分隔符(`" "`).
/// - terminator: 换行 (`"\n"`).
public func print(_ items: Any..., separator: String = " ", terminator: String = "\n")
print
函数需要传入三个参数,参数具体含义已经在代码中注释。其中items
参数是Any
类型,可以传入任何类型。...
代表可变参数,可以传入多个参数。例如:
print("1","2","3","4") //输出1 2 3 4
最后面两个是有默认值的,separator
是分隔符,默认是用空格做分隔符,terminator
默认是换行\n
。当然,传入其他参数来修改默认值,例如:
// 取消分隔符和换行
print("123", separator:"", terminator:"")
print(20) // 打印结果为 12320
// 替换分隔符
print("1","2","3", separator:"+", terminator:"") //打印结果为 1+2+3
print
函数打印外部变量使用\()
:
let age = 18
print("age is \(age)") //打印结果为 age is 18
二、常量
swift中,常量一旦设定,在程序运行时就无法改变其值。所以常量只能赋值1次。
常量可以是任何的数据类型如:整型常量,浮点型常量,字符常量或字符串常量。同样也有枚举类型的常量。
常量的声明
swift中定义常量用let
关键字。
let constA = 42
类型标注
当声明常量或者变量的时候可以加上类型标注(type annotation),用来说明常量或者变量中要存储的值的类型。如果要添加类型标注,需要在常量或者变量名后面加上一个冒号和空格,然后加上类型名称。
let constB: Int = 32
let constC: Float = 3.1415
let constD: Int
constD = 21
上面例子中,常量constD
在声明时指定了数据类型为Int
,所以紧接着将常量constD
赋值为 21,这个操作是允许的。但是如果常量在声明时即没有赋值又没有指定类型,就会报错。例如下面的代码就是错误的:
//错误代码示例
let age
age = 10
需要注意的是,常量和变量在初始化之前都不能使用。 其中,常量的值不要求在编译时期确定,但是在使用之前必须赋值1次。例如下面的常量age
:
func getAge() -> Int {
return 20
}
let age = getAge()
print(age)
常量命名
常量的命名可以由字母,数字和下划线组成。常量需要以字母或下划线开始。
Swift 是一个区分大小写的语言,所以字母大写与小写是不一样的。
三、变量
变量声明
swift中使用 var
关键字声明变量,如下所示:
var varA = 42
print(varA) // 打印输出42
var varB:Float
varB = 3.14159
print("pi is \(varB)")// 打印输出pi is 3.14159
变量命名
变量名可以由字母,数字和下划线组成。
变量名需要以字母或下划线开始。
Swift 是一个区分大小写的语言,所以字母大写与小写是不一样的。
变量名也可以使用简单的 Unicode 字符,如下实例:
四、数据类型
Swift 提供了非常丰富的数据类型,下面用一张表格来简单展示一下Swift 的常见数据类型:
swift跟其他语言不同,仅提供了两大类的数据类型:值类型和引用类型。值类型又包括枚举和结构体两种。我们在OC中常用的Int
、Bool
等基本数据类型在swift中都属于结构体类型。
Int
Swift 提供了一个特殊的整数类型Int
,包括Int8
、Int16
、Int32
、Int64
。长度与当前平台的原生字长相同:
- 在32位平台上,
Int
和Int32
长度相同。 - 在64位平台上,
Int
和Int64
长度相同。
Int8
、Int16
、Int32
、Int64
分别表示 8 位, 16 位, 32 位, 和 64 位的有符号整数形式。
除非你需要特定长度的整数,一般来说使用Int
就够了。这可以提高代码一致性和可复用性。即使是在32位平台上,Int
可以存储的整数范围也可以达到-2,147,483,648
~ 2,147,483,647
,大多数时候这已经足够大了。
UInt
Swift 也提供了一个特殊的无符号类型UInt
,包括UInt8
、UInt16
、UInt32
、UInt64
。长度与当前平台的原生字长相同:
- 在32位平台上,
UInt
和UInt32
长度相同。 - 在64位平台上,
UInt
和UInt64
长度相同。
UInt8
、UInt16
、UInt32
、UInt64
分别表示 8 位, 16 位, 32 位 和 64 位的无符号整数形式。
注意: 尽量不要使用
UInt
,除非你真的需要存储一个和当前平台原生字长相同的无符号整数。除了这种情况,最好使用Int
,即使你要存储的值已知是非负的。统一使用Int
可以提高代码的可复用性,避免不同类型数字之间的转换,并且匹配数字的类型推断。
浮点数:Float、Double
浮点数是有小数部分的数字,比如 3.14159
,0.1
和 -273.15
。
浮点类型比整数类型表示的范围更大,可以存储比 Int
类型更大或者更小的数字。Swift 提供了两种有符号浮点数类型:
- Double 表示64位浮点数。精确度很高,至少有15位数字,当你需要存储很大或者很高精度的浮点数时请使用此类型。
- Float 表示32位浮点数。精度只有6位数字,精度要求不高的话可以使用此类型。
定义Double
类型数据很简单,直接赋值一个小数就可以了,定义Float
类型数据需要声明类型:
let letDouble = 3.12 // Double类型
let letFloat: Float = 3.31 // Float类型
布尔值:Bool
Swift 有一个基本的布尔(Boolean)类型,叫做 Bool
。布尔值指逻辑上的值,因为它们只能是真或者假。Swift 有两个布尔常量,true
和 false
。
五、字面量
字面量,就是指像特定的数字,字符串或者布尔值等,能够直接指出自己的类型并为变量进行赋值的值。比如:
let aNumber = 3 //整型字面量
let aString = "Hello" //字符串字面量
let aBool = true //布尔值字面量
整型字面量
整型字面量可以是一个十进制,二进制,八进制或十六进制常量。 二进制前缀为 0b
,八进制前缀为 0o
,十六进制前缀为 0x
,十进制没有前缀:
let decimalInteger = 17 // 17 - 十进制
let binaryInteger = 0b10001 // 17 - 0b开头,二进制
let octalInteger = 0o21 // 17 - 0o开头,八进制
let hexadecimalInteger = 0x11 // 17 - 0x开头,十六进制
浮点型字面量
浮点型字面量有整数部分,小数点,小数部分及指数部分。
除非特别指定,浮点型字面量的默认推导类型为 Swift 标准库类型中的 Double
,表示64位浮点数。
浮点型字面量默认用十进制表示(无前缀),也可以用十六进制表示(加前缀 0x
)。
let doubleDecimal1 = 125.0 // 十进制,等价于1.25e2 即 1.25 ⨉ 10^2
let doubleDecimal2 = 0.0125 // 十进制,等价于1.25e-2 即 1.25 ⨉ 10^-2
let doubleHexadecimall1= 0xFp2 // 十六进制,0xFp2 表示 15 ⨉ 2^2,也就是十进制的 60.0
let doubleHexadecimall2= 0xFp-2 // 十六进制,0xFp-2 表示 15 ⨉ 2^-2,也就是 3.75
再例如以下都是表示12.1875:
let decimalDouble = 12.1875 //十进制浮点型字面量
let exponentDouble = 1.21875e1 //十进制浮点型字面量
let hexadecimalDouble = 0xC.3p0 //十六进制浮点型字面量
浮点型字面量允许使用下划线 _
来增强数字的可读性,下划线会被系统忽略,因此不会影响字面量的值。同样地,也可以在数字前加 0,并不会影响字面量的值。例如:
let a = 1_000_000 // 1000000
let b = 000123456 //123456
字符串型字面量
字符串型字面量由被包在双引号中的一串字符组成,形式如下:
let name = "mars"
需要注意的是,字符型(Character
)字面量需要声明类型,因为字符型字面量也是使用双引号,所以需要声明类型跟字符串行区别开来:
let char: Character = "a"
类型转换
swift中,整数和浮点数不能直接做运算,需要进行数据类型转换:
let intA = 3
let doubleB = 0.14159
let pi = Double(intA) + doubleB
let intPi = Int(pi)
例子中,intA
为整数,doubleB
为浮点数,类型不同不能直接相加,需要将intA
强转为浮点型,再做运算。相加的结果pi
即浮点型。同样也可以直接将pi
通过Int
关键字强转为Int
类型。
当然,数字字面量可以直接相加,因为本身没有明确类型:
let result = 3 + 0.14159
六、元组(Tuple)
元组是swift语言中一种复合类型,可以将多种类型的数据组合在一起。例如:
let http404Error = (404, "Not Found")
print("The status code is \(http404Error.0)") // 打印输出The status code is 404
例子中的常量 http404Error
就是元组类型,此处为(Int, String)
类型。我们可以通过下标获取常量 http404Error
具体数据内容:
print(http404Error.0) // 打印输出404
print(http404Error.1) // 打印输出Not Found
当然我们也可以用一个元组来接收已经定义好的元组类型常量 http404Error
:
let (statusCode, statusMessage) = http404Error
print("The status code is \(statusCode)") // 打印输出The status code is 404
如果只想不想接收其中某部分数据,使用 _
替代即可:
let (justTheStatusCode, _) = http404Error // 只接收了 http404Error 中Int类型数据
在定义元组类型变量时,也可以给具体值指定标签 标签名+:
,获取时通过点语法即可获取具体值:
let http200Status = (statusCode: 200, description: "success")
print("The status code is \(http200Status.statusCode)") // 打印输出The status code is 200
七、if-else
Swift中,if
后面的条件可以省略小括号,但大括号不可省略。条件只能是Bool
类型。
let grade = 99
if grade >= 90 {
print("Grade is A")
}else if grade >= 80 {
print("Grade is B")
}else if grade >= 70 {
print("Grade is C")
}else {
print("Grade is D")
} // 打印输出Grade is A
八、while
Swift中,while
后面的条件可以省略小括号,但大括号不可省略。
var num = 5
while num > 0 {
print("num is \(num)")
num -= 1
} // 打印输出num is 5 num is 4 num is 3 num is 2 num is 1
注意这里没有使用num--
,是因为在 Swift 3.0 中,就去掉了自增++
和自减--
运算符。
Swift中还提供了repeat - while
语句,相当于C语言中的do - while
语句:
var num1 = -1
repeat {
print("num is \(num1)")
}while num > 0 // 打印输出 num is -1
九、for-in 循环
Swift 中使用for-in
循环用于遍历一个集合里面的所有元素。
var arr = [1, 2, 3, 4, 5]
for index in arr {
print(index)
} // 打印输出 1 2 3 4 5
例子中,index
默认是常量,也可以声明为变量:
var arr = [1,2,3,4,5]
for var index in arr {
print(index)
} // 打印输出 1 2 3 4 5
如果在循环中不需要index
,也可以用 _
替代:
var arr = [1,2,3,4,5]
for _ in arr {
print("hello")
} // 打印输出 hello hello hello hello hello
闭区间运算符 ...
闭区间运算符表示取值范围,例如:
a...b //a <= 取值 <= b
上面for-in
循环的例子就可以写成:
for index in 1...5 {
print(index)
} // 打印输出 1 2 3 4 5
半开区间运算符 ..<
半开区间运算符表示取值范围,例如:
a..
运用到for-in
循环中:
for index in 1..<5 {
print(index)
} // 打印输出 1 2 3 4
区间运算符运用在数组上
上面讲述的区间运算符也可以用在数组上,表示下标值范围:
var names = ["tom", "jack", "mars", "thomas"]
for name in names[0...3] {
print(name)
} // 打印输出tom jack mars thomas
也可以使用单侧区间来指定范围:
// ...2 表示 0 1 2
var names = ["tom", "jack", "mars", "thomas"]
for name in names[...2] {
print(name)
} // 打印输出tom jack mars
使用半开区间运算符:
// ..<2 表示 0 1
var names = ["tom", "jack", "mars", "thomas"]
for name in names[..<2] {
print(name)
} // 打印输出tom jack
十、switch
Swift 中 switch
语句,必须要保证能处理所有情况。switch
语句中case
、default
后面不能写大括号{}
。默认可以不用写 break
,也不会贯穿到后面的条件:
var number = 1
switch number {
case 1:
print("number is 1")
case 2:
print("number is 2")
default:
print("number is other")
} // 打印输出 number is 1
可以使用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
复合条件
除了使用fallthrough
关键字实现复合条件,也可以在条件中写入多个条件并用逗号分隔开。另外,switch
也支持字符串 String
和字符 Character
类型:
let stri = "Mars"
switch stri {
case "Mars", "Tom":
print("He is my friend")
default:
break
} // 打印输出 He is my friend
switch中的区间匹配
区间运算符同样也可以运用到switch
语句中:
let count = 89
switch count {
case 0:
print("none")
case 1..<10:
print("a few")
case 10..<100:
print("a lot")
default:
print("many")
} // 打印输出 a lot
十一、where
swift中可以使用where
关键字来过滤筛选条件:
var numbers = [10, 20, -10, 30, -20]
var sum = 0
for num in numbers where num > 0 {
sum += num
}
print(sum) // 打印输出60
例子中,where num > 0
筛选出数组中的正数,然后进入循环进行相加。
结语
简单学习了一下swift的部分基础语法,今天就到这里,文中如果有不对的地方可以留言指出来。欢迎大家扫码关注微信公众号,一起交流学习。
更多技术知识请扫码关注微信公众号
iOS进阶