Noint's Studio.

Swift语言学习笔记

Word count: 3.4kReading time: 13 min
2024/01/26

关于 Swift

Swift 是一种非常好的编写软件的方式,无论是手机,台式机,服务器,还是其他运行代码的设备。它是一种安全,快速和互动的编程语言,将现代编程语言的精华和苹果工程师文化的智慧,以及来自开源社区的多样化贡献结合了起来。编译器对性能进行了优化,编程语言对开发进行了优化,两者互不干扰,鱼与熊掌兼得。

Swift 对于初学者来说也很友好。它是一门满足工业标准的编程语言,但又有着脚本语言般的表达力和可玩性。它支持代码预览(playgrounds),这个革命性的特性可以允许程序员在不编译和运行应用程序的前提下运行 Swift 代码并实时查看结果。

Swift 通过采用现代编程模式来避免大量常见编程错误:

  • 变量始终在使用前初始化。
  • 检查数组索引超出范围的错误。
  • 检查整数是否溢出。
  • 可选值确保明确处理 nil 值。
  • 内存被自动管理。
  • 错误处理允许从意外故障控制恢复。

Swift 代码被编译和优化,以充分利用现代硬件。语法和标准库是基于指导原则设计的,编写代码的明显方式也应该是最好的。安全性和速度的结合使得 Swift 成为从 “Hello,world!” 到整个操作系统的绝佳选择。

关于语法细节可参考:https://swift.bootcss.com/

语法笔记

2.1 说明

Swift 包含了 C 和 Objective-C 上所有基础数据类型,Int 表示整型值; DoubleFloat 表示浮点型值; Bool 是布尔型值;String 是文本型数据。 Swift 还提供了三个基本的集合类型,ArraySetDictionary

就像 C 语言一样,Swift 使用变量来进行存储并通过变量名来关联值。在 Swift 中,广泛的使用着值不可变的变量,它们就是常量,而且比 C 语言的常量更强大。在 Swift 中,如果你要处理的值不需要改变,那使用常量可以让你的代码更加安全并且更清晰地表达你的意图。

除了我们熟悉的类型,Swift 还增加了 Objective-C 中没有的高阶数据类型比如元组(Tuple)。元组可以让你创建或者传递一组数据,比如作为函数的返回值时,你可以用一个元组可以返回多个值。

Swift 还增加了可选(Optional)类型,用于处理值缺失的情况。可选表示 “那儿有一个值,并且它等于 x ” 或者 “那儿没有值” 。可选有点像在 Objective-C 中使用 nil ,但是它可以用在任何类型上,不仅仅是类。可选类型比 Objective-C 中的 nil 指针更加安全也更具表现力,它是 Swift 许多强大特性的重要组成部分。

Swift 是一门 类型安全 的语言,这意味着 Swift 可以让你清楚地知道值的类型。如果你的代码需要一个 String ,类型安全会阻止你不小心传入一个 Int 。同样的,如果你的代码需要一个 String,类型安全会阻止你意外传入一个可选的 String 。类型安全可以帮助你在开发阶段尽早发现并修正错误。

2.2 基础类型

1)变量与常量

声明常量和变量

常量和变量必须在使用前声明,用 let 来声明常量,用 var 来声明变量。下面的例子展示了如何用常量和变量来记录用户尝试登录的次数:

1
2
let maximumNumberOfLoginAttempts = 10
var currentLoginAttempt = 0

这两行代码可以被理解为:

“声明一个名字是 maximumNumberOfLoginAttempts 的新常量,并给它一个值 10 。然后,声明一个名字是 currentLoginAttempt 的变量并将它的值初始化为 0 。”

类型注解

当你声明常量或者变量的时候可以加上 类型注解(type annotation) ,说明常量或者变量中要存储的值的类型。如果要添加类型注解,需要在常量或者变量名后面加上一个冒号和空格,然后加上类型名称。

这个例子给 welcomeMessage 变量添加了类型注解,表示这个变量可以存储 String 类型的值:

1
var welcomeMessage: String

声明中的冒号代表着 “是…类型” ,所以这行代码可以被理解为:

“声明一个类型为 String ,名字为 welcomeMessage 的变量。”

“类型为 String ”的意思是“可以存储任意 String 类型的值。”

welcomeMessage 变量现在可以被设置成任意字符串:

1
welcomeMessage = "Hello"

常量和变量名可以包含几乎所有的字符,包括 Unicode 字符:

1
2
3
let π = 3.14159
let 你好 = "你好世界"
let 🐶🐮 = "dogcow"

值得注意的是:

a)在实际项目开发中,应该优先使用 let 类型,如需修改时再改为 var

b)let 指的是地址不可修改,但对象内容是可修改的(常量不可修改)。

2)元组(tuples)

把多个值组合成一个复合值。元组内的值可以是任意类型,并不要求是相同类型。

下面这个例子中,(404, "Not Found") 是一个描述 HTTP 状态码(HTTP status code) 的元组。HTTP 状态码是当你请求网页的时候 web 服务器返回的一个特殊值。如果你请求的网页不存在就会返回一个 404 Not Found 状态码。

1
2
let http404Error = (404, "Not Found")
// http404Error 的类型是 (Int, String),值是 (404, "Not Found")

(404, "Not Found") 元组把一个 Int 值和一个 String 值组合起来表示 HTTP 状态码的两个部分:一个数字和一个人类可读的描述。这个元组可以被描述为“一个类型为 (Int, String) 的元组”。

你可以把任意顺序的类型组合成一个元组,这个元组可以包含所有类型。只要你想,你可以创建一个类型为 (Int, Int, Int) 或者 (String, Bool) 或者其他任何你想要的组合的元组。

你可以将一个元组的内容分解(decompose)成单独的常量和变量,然后你就可以正常使用它们了:

1
2
3
4
5
let (statusCode, statusMessage) = http404Error
print("The status code is \(statusCode)")
// 输出“The status code is 404”
print("The status message is \(statusMessage)")
// 输出“The status message is Not Found”

如果你只需要一部分元组值,分解的时候可以把要忽略的部分用下划线(_)标记:

1
2
3
let (justTheStatusCode, _) = http404Error
print("The status code is \(justTheStatusCode)")
// 输出“The status code is 404”

此外,你还可以通过下标来访问元组中的单个元素,下标从零开始:

1
2
3
4
print("The status code is \(http404Error.0)")
// 输出“The status code is 404”
print("The status message is \(http404Error.1)")
// 输出“The status message is Not Found”

你可以在定义元组的时候给单个元素命名:

1
let http200Status = (statusCode: 200, description: "OK")

给元组中的元素命名后,你可以通过名字来获取这些元素的值:

1
2
3
4
print("The status code is \(http200Status.statusCode)")
// 输出“The status code is 200”
print("The status message is \(http200Status.description)")
// 输出“The status message is OK”

作为函数返回值时,元组非常有用。一个用来获取网页的函数可能会返回一个 (Int, String) 元组来描述是否获取成功。和只能返回一个类型的值比较起来,一个包含两个不同类型值的元组可以让函数的返回信息更有用。请参考 函数参数与返回值

3)可选类型

可选类型用于处理可能缺失的情况。例如:

1
2
3
var surveyAnswer: String? = "123"
let possibleNumber = "123"
let convertedNumber = Int(possibleNumber)

使用 if 或者 while 进行值判断。例如:

1
2
3
4
5
6
7
// 强制解包
let value = surveyAnswer!

// 可选绑定
if let newString = surveyAnswer {
// ...
}

4)值类型与引用类型

值类型在赋值或传递时会进行拷贝。引用类型增加引用计数,不进行拷贝。

5)其他

5.1) 类型别名:

Swift 中不使用 typedef,而是使用 typealias

1
typealias AudioSample = UInt16

5.2) 分号:

Swift 中不需要使用分号,但同一行的两个语句可以使用分号分隔。

2.3 运算符

1)空合运算符

空合运算符a ?? b)将对可选类型 a 进行空判断,如果 a 包含一个值就进行解包,否则就返回一个默认值 b。表达式 a 必须是 Optional 类型。默认值 b 的类型必须要和 a 存储值的类型保持一致。

空合运算符是对以下代码的简短表达方法:

1
a != nil ? a! : b

上述代码使用了三元运算符。当可选类型 a 的值不为空时,进行强制解包(a!),访问 a 中的值;反之返回默认值 b。无疑空合运算符(??)提供了一种更为优雅的方式去封装条件判断和解包两种行为,显得简洁以及更具可读性。

2)区间运算符

Swift 提供了多种区间运算符,例如闭区间运算符 a...b 和半开区间运算符 a..<b

2.4 字符与字符串

Swift 的 StringCharacter 类型兼容 Unicode,允许使用任何字符。例如:

1
2
3
for character in "Dog!🐶" {
print(character)
}

String 是值类型。

2.5 控制流

1)if 语句

if 的条件必须是布尔表达式。例如:

1
2
3
4
5
6
7
8
9
10
let individualScores = [75, 43, 103, 87, 12]
var teamScore = 0
for score in individualScores {
if score > 50 {
teamScore += 3
} else {
teamScore += 1
}
}
print(teamScore)

2)switch 语句

switch 支持任意类型的数据和多种比较操作。例如:

1
2
3
4
5
6
7
let vegetable = "red pepper"
switch vegetable {
case "celery":
print("Add some raisins and make ants on a log.")
default:
print("Everything tastes good in soup.")
}

感谢您的提醒,我将在原来的结构基础上添加这部分内容关于函数的说明:


2.6 函数

1)函数的定义

Swift 中函数的定义格式如下:

1
2
3
func funcName(parameters) -> returnType {
// function body
}

例如,定义一个问候函数:

1
2
3
4
func greet(person: String) -> String {
let greeting = "Hello, " + person + "!"
return greeting
}

这里的函数格式类似于 JavaScript,但是增加了返回值类型的定义。

2)参数列表

a)参数标签和参数名称

每个函数参数都有一个参数标签(argument label)和一个参数名称(parameter name)。参数标签在调用函数时使用,参数名称在函数的实现中使用。默认情况下,参数名称作为其参数标签。

1
2
3
func someFunction(parameterName: Int) {
// 在函数体内,parameterName 代表参数值
}

b)省略参数标签

如果不希望为某个参数添加标签,可以使用下划线(_)来代替明确的参数标签。

1
2
3
4
func someFunction(_ firstParameterName: Int, secondParameterName: Int) {
// 函数体
}
someFunction(1, secondParameterName: 2)

c)默认参数

类似于 C++,Swift 函数也可以有默认参数值。

1
2
3
4
5
func someFunction(parameterWithoutDefault: Int, parameterWithDefault: Int = 12) {
// 函数体
}
someFunction(parameterWithoutDefault: 3, parameterWithDefault: 6) // parameterWithDefault = 6
someFunction(parameterWithoutDefault: 4) // parameterWithDefault = 12

d)可变参数

函数可以接受不确定数量的参数,通过在参数类型后面添加 ... 来定义。

1
2
3
4
5
6
7
func arithmeticMean(_ numbers: Double...) -> Double {
var total: Double = 0
for number in numbers {
total += number
}
return total / Double(numbers.count)
}

e)输入输出参数

使用 inout 关键字定义输入输出参数,允许函数修改参数的值。

1
2
3
4
5
func swapTwoInts(_ a: inout Int, _ b: inout Int) {
let temporaryA = a
a = b
b = temporaryA
}

3)函数类型

函数类型类似于函数指针,由函数的参数类型和返回类型组成。

1
2
3
4
5
func addTwoInts(_ a: Int, _ b: Int) -> Int {
return a + b
}

var mathFunction: (Int, Int) -> Int = addTwoInts

函数类型可以作为参数类型、返回值类型等。

2.7 闭包

Swift 中的闭包类似于 OC 的 Block 和 C++ 的 lambda 表达式。闭包的一般形式为:

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

闭包可以用于排序等操作。例如:

1
2
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
let reversedNames = names.sorted(by: { $0 > $1 })

闭包是引用类型。

2.8 枚举、结构体、类

1)枚举

Swift 中的枚举更加灵活,不必为每个成员提供值。枚

举成员可以有关联值。例如:

1
2
3
4
5
6
enum CompassPoint {
case north
case south
case east
case west
}

2)结构体与类

结构体是值类型,类是引用类型。结构体和类有很多相似之处。例如:

1
2
3
4
5
6
struct SomeStructure {
// 结构体定义
}
class SomeClass {
// 类定义
}

2.9 类的构造与析构

类的构造和析构与 C++ 类似,但语法上有所不同。例如:

1
2
3
4
5
6
7
8
class Color {
var red, green, blue: Double
init(red: Double, green: Double, blue: Double) {
self.red = red
self.green = green
self.blue = blue
}
}

2.10 属性监听器

属性监听器可以在属性即将改变或已经改变时执行代码。例如:

1
2
3
4
5
6
7
8
9
10
class SomeClass {
var name: String {
willSet {
// 即将改变
}
didSet {
// 已经改变
}
}
}

2.11 类的继承

Swift 支持类的继承。子类可以重写父类的方法、属性和下标。例如:

1
2
3
class Bicycle: Vehicle {
var hasBasket = false
}

2.12 扩展

扩展可以给现有的类、结构体、枚举或协议添加新功能。例如:

1
2
3
extension SomeType {
// 添加的新功能
}

2.13 协议

协议定义了一组方法、属性或其他要求,用于满足特定任务或功能。例如:

1
2
3
protocol SomeProtocol {
// 协议定义
}

2.14 泛型

Swift 的泛型允许你写出灵活、可重用的函数和类型。它可以避免重复的代码,用一种清晰的方式来表达代码的意图。

CATALOG
  1. 1. 关于 Swift
  2. 2. 语法笔记
    1. 2.1. 2.1 说明
    2. 2.2. 2.2 基础类型
      1. 2.2.1. 1)变量与常量
        1. 2.2.1.1. 声明常量和变量
        2. 2.2.1.2. 类型注解
      2. 2.2.2. 2)元组(tuples)
      3. 2.2.3. 3)可选类型
      4. 2.2.4. 4)值类型与引用类型
      5. 2.2.5. 5)其他
        1. 2.2.5.1. 5.1) 类型别名:
        2. 2.2.5.2. 5.2) 分号:
    3. 2.3. 2.3 运算符
      1. 2.3.1. 1)空合运算符
      2. 2.3.2. 2)区间运算符
    4. 2.4. 2.4 字符与字符串
    5. 2.5. 2.5 控制流
      1. 2.5.1. 1)if 语句
      2. 2.5.2. 2)switch 语句
    6. 2.6. 2.6 函数
      1. 2.6.1. 1)函数的定义
      2. 2.6.2. 2)参数列表
        1. 2.6.2.1. a)参数标签和参数名称
        2. 2.6.2.2. b)省略参数标签
        3. 2.6.2.3. c)默认参数
        4. 2.6.2.4. d)可变参数
        5. 2.6.2.5. e)输入输出参数
      3. 2.6.3. 3)函数类型
    7. 2.7. 2.7 闭包
    8. 2.8. 2.8 枚举、结构体、类
      1. 2.8.1. 1)枚举
      2. 2.8.2. 2)结构体与类
    9. 2.9. 2.9 类的构造与析构
    10. 2.10. 2.10 属性监听器
    11. 2.11. 2.11 类的继承
    12. 2.12. 2.12 扩展
    13. 2.13. 2.13 协议
    14. 2.14. 2.14 泛型