新手必看:Swift 编程快速入门教程 – wiki基地


新手必看:Swift 编程快速入门教程

恭喜你迈出学习编程的第一步,并选择了 Swift 这门现代、强大且富有表现力的语言!Swift 是 Apple 公司于 2014 年推出的一门通用编程语言,旨在替代 C、C++ 和 Objective-C,用于开发 iOS、macOS、watchOS、tvOS 等 Apple 平台上的应用。近年来,Swift 也凭借其出色的性能和易用性,在服务器端开发、机器学习等领域崭露头角。

这篇教程将为你详细介绍 Swift 的基本概念,带你从零开始,一步步掌握编写 Swift 代码所需的知识。无论你将来想开发 App、写服务器代码还是探索更多可能性,Swift 都将是一个优秀的起点。

我们将涵盖以下主题:

  1. Swift 是什么?为什么选择 Swift?
  2. 搭建开发环境:Xcode 与 Swift Playgrounds
  3. 你的第一个 Swift 程序:Hello, World!
  4. 变量与常量:varlet
  5. 基本数据类型:整数、浮点数、布尔值、字符串
  6. 类型安全与类型推断
  7. 基本运算符
  8. 控制流:条件语句 (if/else, switch) 与循环 (for-in, while, repeat-while)
  9. 集合类型:数组 (Array)、字典 (Dictionary)、集合 (Set)
  10. 函数:定义、调用、参数与返回值
  11. Optionals (可选类型):处理值可能缺失的情况
  12. 结构体 (Structs) 与类 (Classes) 的初步认识
  13. 枚举 (Enums)
  14. 接下来的学习方向

本教程内容较多,建议你耐心阅读,并动手在 Swift Playground 中实际运行代码,这样才能更好地理解和掌握。

1. Swift 是什么?为什么选择 Swift?

Swift 是什么?

Swift 是一门多范式(支持面向对象、函数式、协议导向等)的编译型编程语言。它的设计目标是安全、快速和富有表现力。

  • 安全 (Safe): Swift 引入了许多语言特性来避免常见的编程错误,例如 Optionals(可选类型)强制你处理值可能缺失的情况,避免了空指针错误;类型安全系统防止了类型不匹配的错误。
  • 快速 (Fast): Swift 使用了高性能的 LLVM 编译器,代码可以被编译成高度优化的机器码,性能接近 C/C++/Objective-C。
  • 富有表现力 (Expressive): Swift 的语法简洁易懂,支持现代编程范式,可以用更少的代码表达复杂的思想。

为什么选择 Swift?

  • Apple 生态系统: 如果你想开发 iPhone、iPad、Mac 等设备的 App,Swift 是首选语言。
  • 现代语言特性: 继承了多种语言的优点,语法糖多,写起来更舒服。
  • 强大的社区与生态: 拥有活跃的开发者社区和丰富的第三方库。
  • 开源: Swift 是开源项目,任何人都可以贡献和改进它。
  • 性能优异: 适合对性能要求较高的场景。
  • 易于学习(相对于 Objective-C): 语法更贴近自然语言,去掉了 Objective-C 中复杂的语法(如头文件、指针操作、消息发送语法 [object method] 等)。

总而言之,学习 Swift 是一项非常有价值的投资,尤其如果你对 Apple 开发感兴趣的话。

2. 搭建开发环境:Xcode 与 Swift Playgrounds

学习 Swift 的最主要工具是 Xcode。Xcode 是 Apple 提供的集成开发环境(IDE),用于开发 macOS、iOS、watchOS 和 tvOS 应用程序。它包含了编写代码、UI 设计、调试、性能分析等全方位工具。

安装 Xcode:

  1. 如果你使用 macOS,直接在 Mac App Store 中搜索并下载 Xcode。它是免费的。
  2. 安装过程可能需要一些时间,因为它是一个庞大的应用。
  3. 安装完成后,打开 Xcode。

Swift Playgrounds:

对于初学者来说,Swift Playgrounds 是一个极好的实验和学习工具。它是一个交互式环境,你可以直接在其中编写 Swift 代码,并立即看到结果。无需创建完整的项目,非常适合用来测试代码片段、学习语法。

在 Xcode 中使用 Swift Playgrounds:

  1. 打开 Xcode。
  2. 选择菜单栏的 File > New > Playground...
  3. 选择一个模板(例如 Blank),点击 Next
  4. 给你的 Playground 命名,选择保存位置,点击 Create

一个新的 Playground 窗口就会打开。左侧是代码编辑区域,右侧(或底部)会显示代码的运行结果。

“`swift
import UIKit // 或者 Foundation,看你创建的模板

var greeting = “Hello, playground”

print(greeting) // 在控制台输出结果
“`

在 Playground 中,你写下的每一行代码都会被 Playground 自动执行(或者当你点击运行按钮后执行),并在右侧的侧边栏显示这行代码的结果。print() 函数的输出会在下方的控制台区域显示。

本教程中的代码示例,你都可以直接在 Swift Playground 中输入并运行,以便观察效果。

3. 你的第一个 Swift 程序:Hello, World!

按照上面的步骤创建一个新的 Playground。默认情况下,它可能已经包含一些代码。你可以把它们删掉,然后输入下面这行代码:

swift
print("Hello, World!")

如果 Playground 设置为自动运行,你会在右侧或下方的控制台区域看到输出:

Hello, World!

恭喜!你已经成功编写并运行了你的第一个 Swift 程序。

  • print() 是一个 Swift 内置的函数,用于向控制台输出内容。
  • "Hello, World!" 是一个字符串字面量,即直接写在代码中的文本值。字符串在 Swift 中用双引号 " 包围。

4. 变量与常量:varlet

在编程中,我们经常需要存储和操作数据。变量常量就是用来在内存中存储值的容器。

  • 常量 (Constant): 使用 let 关键字声明。一旦赋值后,其值就不能再改变。
  • 变量 (Variable): 使用 var 关键字声明。其值可以在后续代码中修改。

声明常量:

“`swift
let maximumNumberOfLoginAttempts = 10
let pi = 3.14159
let welcomeMessage = “Hello”

// 尝试修改常量会报错:
// maximumNumberOfLoginAttempts = 5 // ❌ Error: Cannot assign to value: ‘maximumNumberOfLoginAttempts’ is a ‘let’ constant
“`

声明变量:

“`swift
var currentLoginAttempt = 0
var volume = 5.0
var greeting = “你好”

// 可以修改变量的值:
currentLoginAttempt = currentLoginAttempt + 1 // 或者更简洁地写 currentLoginAttempt += 1
volume = volume * 2.0 // volume 现在是 10.0
greeting = “嗨!” // greeting 现在是 “嗨!”
“`

什么时候用 let,什么时候用 var

Swift 推荐优先使用 let 来声明常量。 只有当确定某个值将来需要修改时,才使用 var 声明为变量。这样做的好处是:

  • 提高代码安全性: 避免了意外修改不应该改变的值。
  • 提高代码可读性: 读者一眼就知道这个值是固定不变的。
  • 性能优化: 编译器对常量可以做更多的优化。

这是一个非常重要的 Swift 编程习惯,请务必养成!

5. 基本数据类型:整数、浮点数、布尔值、字符串

Swift 提供了多种基本数据类型来表示不同种类的值。

  • 整数 (Integers): 表示没有小数部分的数字。
    • Int: 标准整数类型,长度通常与当前平台的原生字长相同(在 32 位系统上是 32 位,在 64 位系统上是 64 位)。它是最常用的整数类型。
    • UInt: 无符号整数,只能存储非负数。较少使用,通常只在需要特定大小的无符号整数时使用。
    • 还有其他特定大小的整数类型,如 Int8, UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64

swift
let age: Int = 30
let year: Int = 2023
let bigNumber: Int64 = 1234567890123456789
let positiveNumber: UInt = 100 // 不能是负数

  • 浮点数 (Floating-Point Numbers): 表示带有小数部分的数字。
    • Double: 表示 64 位浮点数,精度更高,是默认的浮点数类型。
    • Float: 表示 32 位浮点数,精度较低。

swift
let price: Double = 19.99
let gravity: Double = 9.8
let temperature: Float = 36.5 // 显式指定为 Float

  • 布尔值 (Booleans): 表示逻辑值,只有两个可能的值:truefalse
    • Bool: 用于表示真假状态。

swift
let isStudent: Bool = true
let hasPermission: Bool = false

  • 字符串 (Strings): 表示文本序列。Swift 的 String 类型功能强大且易于使用。

“`swift
let greeting = “Hello”
let name = “Alice”
let message = greeting + “, ” + name + “!” // 字符串拼接
print(message) // 输出: Hello, Alice!

// 字符串插值 (String Interpolation) – 更推荐的方式
let studentAge = 20
let info = “学生 (name) 的年龄是 (studentAge)。”
print(info) // 输出: 学生 Alice 的年龄是 20。
“`

字符串插值允许你将变量、常量或其他表达式的值直接嵌入到字符串字面量中,用 \(...) 包围。这使得构建复杂的字符串变得非常简洁。

6. 类型安全与类型推断

Swift 是一门类型安全的语言。这意味着 Swift 会在编译时检查你的代码,确保你不会对一个变量赋值错误类型的值。如果你尝试将一个 Int 类型的值赋给一个声明为 String 的变量,编译器就会报错。

swift
var score: Int = 100
// score = "优秀" // ❌ Error: Cannot assign value of type 'String' to type 'Int'

这种类型安全性帮助你在开发早期捕获错误,避免了许多运行时问题。

类型推断 (Type Inference):

虽然 Swift 是类型安全的,但这不意味着你必须在使用前总是显式地指定每个变量或常量的类型。Swift 具有强大的类型推断能力。当你为一个变量或常量赋初值时,Swift 编译器可以根据赋的值自动推断出它的类型。

swift
let meaningOfLife = 42 // Swift 推断出 meaningOfLife 是 Int 类型
let pi = 3.14159 // Swift 推断出 pi 是 Double 类型
let anotherGreeting = "你好,世界!" // Swift 推断出 anotherGreeting 是 String 类型
let swiftIsAwesome = true // Swift 推断出 swiftIsAwesome 是 Bool 类型

在上面的例子中,我们没有写 : Int: Double 等类型标注,Swift 编译器会自动根据右边的值推断出左边的类型。

在 Swift 编程中,推荐在编译器可以推断出类型时,省略类型标注,使代码更简洁。只有在以下情况时,你可能需要显式指定类型:

  • 初始化时没有赋初值。
  • 需要指定一个编译器无法准确推断的类型(例如,想指定 Float 而不是默认的 Double)。
  • 为了代码的可读性,让类型更加清晰。

7. 基本运算符

Swift 支持大多数标准的运算符。

  • 算术运算符: + (加), - (减), * (乘), / (除), % (取余)

swift
let a = 10
let b = 3
let sum = a + b // 13
let difference = a - b // 7
let product = a * b // 30
let division = a / b // 3 (整数除法,结果仍为整数)
let remainder = a % b // 1

注意:Swift 不允许直接对不同数字类型(如 IntDouble)执行算术运算。你需要进行类型转换。

swift
let intValue: Int = 5
let doubleValue: Double = 2.5
// let result = intValue + doubleValue // ❌ Error
let result = Double(intValue) + doubleValue // ✅ result = 7.5

  • 赋值运算符: = (赋值)

swift
var x = 10

  • 复合赋值运算符: +=, -=, *=, /=, %=

swift
var count = 0
count += 1 // count = count + 1
var total = 100
total -= 20 // total = total - 20

  • 比较运算符: == (等于), != (不等于), > (大于), < (小于), >= (大于等于), <= (小于等于)
    比较运算符的结果是布尔值 (Bool)。

swift
let isEqual = (5 == 5) // true
let isNotEqual = (5 != 10) // true
let isGreater = (10 > 5) // true

  • 逻辑运算符: && (逻辑与), || (逻辑或), ! (逻辑非)
    逻辑运算符用于组合布尔值或布尔表达式。

“`swift
let isSunny = true
let isWarm = false

let shouldGoOutside = isSunny && isWarm // false (必须两个都为真)
let canRelax = isSunny || isWarm // true (只要一个为真)
let isNotWarm = !isWarm // true (取反)
“`

8. 控制流:条件语句与循环

控制流允许你根据条件执行不同的代码块,或者重复执行某段代码。

条件语句

  • if / else if / else

用于根据一个或多个条件执行代码。条件必须是布尔值。

“`swift
let temperature = 25

if temperature < 0 {
print(“非常冷!”)
} else if temperature >= 0 && temperature < 10 {
print(“有点冷。”)
} else if temperature >= 10 && temperature < 20 {
print(“凉爽。”)
} else if temperature >= 20 && temperature < 30 {
print(“舒适。”)
} else {
print(“有点热!”)
}
“`

  • switch

switch 语句用于将一个值与多个可能的模式进行匹配。Swift 的 switch 比 C 语言等更强大,不需要在每个 case 后面写 break,因为它默认不会“穿透”到下一个 caseswitch 语句必须是穷尽的(exhaustive),即必须处理所有可能的取值,或者提供一个 default 分支。

“`swift
let score = 95

switch score {
case 0..<60: // 范围匹配 (0 到 59)
print(“不及格”)
case 60..<80: // 范围匹配 (60 到 79)
print(“及格”)
case 80..<90: // 范围匹配 (80 到 89)
print(“良好”)
case 90…100: // 闭区间匹配 (90 到 100)
print(“优秀”)
default: // 处理所有其他可能的情况
print(“分数无效”)
}
“`

switch 语句还支持元组匹配、值绑定、where 子句等高级功能,这里只展示基础用法。

循环

  • for-in 循环

for-in 循环用于遍历序列(sequence),例如数字范围、数组中的元素、字典的键值对、字符串中的字符等。

“`swift
// 遍历数字范围
for i in 1…5 { // 闭区间: 包含 1 和 5
print(“Count is (i)”)
}
// 输出: Count is 1, Count is 2, Count is 3, Count is 4, Count is 5

for j in 1..<5 { // 半开区间: 包含 1,不包含 5
print(“J is (j)”)
}
// 输出: J is 1, J is 2, J is 3, J is 4

// 遍历数组
let fruits = [“Apple”, “Banana”, “Cherry”]
for fruit in fruits {
print(“我喜欢吃 (fruit)。”)
}
// 输出: 我喜欢吃 Apple。, 我喜欢吃 Banana。, 我喜欢吃 Cherry。

// 遍历字典
let colors = [“red”: “红色”, “blue”: “蓝色”, “green”: “绿色”]
for (key, value) in colors {
print(“(key) 的中文是 (value)。”)
}
// 输出可能顺序不定: red 的中文是 红色。, blue 的中文是 蓝色。, green 的中文是 绿色。

// 如果你不需要循环中的值,可以用 _ 代替
for _ in 1…3 {
print(“Hello!”)
}
// 输出: Hello!, Hello!, Hello!
“`

  • while 循环

while 循环在条件为 true 时重复执行一个代码块。条件在每次循环迭代开始时检查。

“`swift
var countdown = 3

while countdown > 0 {
print(“(countdown)…”)
countdown -= 1 // 记住在循环体内改变条件,否则可能无限循环
}
print(“Go!”)
// 输出: 3…, 2…, 1…, Go!
“`

  • repeat-while 循环

repeat-while 循环与 while 类似,但它是在每次循环迭代结束时检查条件。这意味着循环体至少会被执行一次。

“`swift
var index = 0

repeat {
print(“Index is (index)”)
index += 1
} while index < 3
// 输出: Index is 0, Index is 1, Index is 2
“`

9. 集合类型:数组、字典、集合

Swift 提供了三种主要的集合类型来存储值的集合。这些集合是泛型的,意味着它们可以存储任何指定类型的值。

  • 数组 (Array): 有序的值的集合。数组中的每个值都有一个对应的索引(从 0 开始)。
    • 声明:[Element]Array<Element>
    • 创建空数组:var someInts: [Int] = []var anotherInts = [Int]()
    • 创建带初始值的数组:var shoppingList = ["Eggs", "Milk", "Bread"]

“`swift
var fruits = [“Apple”, “Banana”, “Cherry”] // 类型推断为 [String]

print(fruits.count) // 3 (元素个数)
print(fruits[0]) // “Apple” (访问第一个元素)

fruits.append(“Orange”) // 添加元素到末尾
print(fruits) // [“Apple”, “Banana”, “Cherry”, “Orange”]

fruits.insert(“Mango”, at: 1) // 在指定索引插入
print(fruits) // [“Apple”, “Mango”, “Banana”, “Cherry”, “Orange”]

fruits.remove(at: 0) // 移除指定索引的元素
print(fruits) // [“Mango”, “Banana”, “Cherry”, “Orange”]

// 遍历数组
for fruit in fruits {
print(fruit)
}
“`

  • 字典 (Dictionary): 无序的键值对集合。每个值都与一个唯一的键 (Key) 相关联,可以通过键来访问对应的值。键必须是可哈希 (Hashable) 的(Swift 的基本类型如 String, Int, Double, Bool 等都是可哈希的)。
    • 声明:[Key: Value]Dictionary<Key, Value>
    • 创建空字典:var namesOfIntegers: [Int: String] = [:]var anotherDict = [String: Int]()
    • 创建带初始值的字典:var airports = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]

“`swift
var studentAges = [“Alice”: 20, “Bob”: 22, “Charlie”: 21] // 类型推断为 [String: Int]

print(studentAges.count) // 3 (键值对个数)

print(studentAges[“Alice”]) // Optional(20) (通过键访问值,结果是 Optional,后面会解释)
print(studentAges[“David”]) // nil (键不存在,结果是 nil)

studentAges[“David”] = 23 // 添加新的键值对
studentAges[“Alice”] = 21 // 修改已有键的值
print(studentAges) // [“Alice”: 21, “Bob”: 22, “Charlie”: 21, “David”: 23] (顺序可能不定)

studentAges[“Bob”] = nil // 通过赋 nil 移除键值对
// 或者使用 removeValue(forKey:) 方法: studentAges.removeValue(forKey: “Charlie”)
print(studentAges) // [“Alice”: 21, “Charlie”: 21, “David”: 23]

// 遍历字典
for (name, age) in studentAges {
print(“(name) is (age) years old.”)
}

// 只遍历键
for name in studentAges.keys {
print(“学生姓名: (name)”)
}

// 只遍历值
for age in studentAges.values {
print(“学生年龄: (age)”)
}
“`

  • 集合 (Set): 无序的唯一值的集合。集合中的值必须是可哈希的。主要用于快速检查某个值是否存在,或者执行集合间的操作(交集、并集等)。
    • 声明:Set<Element>
    • 创建空集合:var letters = Set<Character>()
    • 创建带初始值的集合:var favoriteGenres: Set<String> = ["Rock", "Classical", "Hip hop"] 或通过数组字面量创建并指定类型 var numbers: Set = [1, 2, 3, 1, 2] (重复的值会被忽略)

“`swift
var distinctNumbers: Set = [1, 2, 3, 1, 4, 2] // {1, 2, 3, 4} (重复项被移除,顺序不定)

print(distinctNumbers.count) // 4

distinctNumbers.insert(5) // 添加元素
print(distinctNumbers) // {1, 2, 3, 4, 5}

print(distinctNumbers.contains(3)) // true (检查元素是否存在)
print(distinctNumbers.contains(6)) // false

distinctNumbers.remove(1) // 移除元素
print(distinctNumbers) // {2, 3, 4, 5}

// 遍历集合
for number in distinctNumbers {
print(number) // 顺序不定
}
“`

像数组和字典一样,如果使用 let 声明集合,则集合是不可变的;使用 var 声明则可变。

10. 函数

函数是组织代码块,使其可以多次调用,并且可以接受输入(参数)并产生输出(返回值)的方式。

定义函数:

使用 func 关键字定义函数。

“`swift
// 一个没有参数,没有返回值的函数
func greet() {
print(“Hello!”)
}

greet() // 调用函数

// 一个带参数,没有返回值的函数
func greet(person name: String) { // person 是 argument label (参数标签), name 是 parameter name (参数名)
print(“Hello, (name)!”)
}

greet(person: “Alice”) // 调用函数,必须使用参数标签 person

// 如果不想使用参数标签,可以在参数名前面加上 _
func greetAgain(_ name: String) {
print(“Hello again, (name)!”)
}

greetAgain(“Bob”) // 调用函数,不需要参数标签

// 一个带多个参数,有返回值的函数
func addNumbers(a: Int, b: Int) -> Int { // -> Int 表示函数返回一个 Int 类型的值
let sum = a + b
return sum // 使用 return 关键字返回值
}

let result = addNumbers(a: 5, b: 3) // 调用函数,使用参数标签 a 和 b
print(result) // 8

// 一个函数可以返回一个元组,从而返回多个值
func calculateStats(numbers: [Double]) -> (sum: Double, average: Double, min: Double, max: Double)? {
if numbers.isEmpty {
return nil // 如果数组为空,返回 nil (这是一个 Optional 元组)
}

var sum = 0.0
var min = numbers[0]
var max = numbers[0]

for number in numbers {
    sum += number
    if number < min {
        min = number
    }
    if number > max {
        max = number
    }
}
let average = sum / Double(numbers.count)
return (sum, average, min, max) // 返回一个元组

}

let stats = calculateStats(numbers: [1.0, 2.0, 3.0, 4.0, 5.0])

// 通过 Optional Binding 安全地解包返回的元组
if let statistics = stats {
print(“Sum: (statistics.sum), Average: (statistics.average), Min: (statistics.min), Max: (statistics.max)”)
} else {
print(“输入数组为空。”)
}

// 函数参数可以有默认值
func sendMessage(message: String, to recipient: String = “所有人”) {
print(“发送消息 ‘(message)’ 给 (recipient)”)
}

sendMessage(message: “会议通知”) // 使用默认的收件人 “所有人”
sendMessage(message: “祝你生日快乐”, to: “Bob”) // 指定收件人 Bob

// 函数参数可以是可变参数 (variadic parameters)
func average(_ numbers: Double…) -> Double { // numbers 是一个 [Double] 数组
var total = 0.0
for number in numbers {
total += number
}
return total / Double(numbers.count)
}

let avg1 = average(1.0, 2.0, 3.0) // avg1 是 2.0
let avg2 = average(5.0, 10.0, 15.0, 20.0) // avg2 是 12.5
“`

函数的定义和调用是 Swift 中非常核心的概念,理解参数标签、参数名以及如何处理返回值非常重要。

11. Optionals (可选类型)

Optionals 是 Swift 中一个非常重要的概念,用于处理值可能缺失的情况。

在很多编程语言中,如果一个变量没有值,它可能被设置为一个特殊的空值(比如 Java/C++ 的 null 或 Objective-C 的 nil)。然而,尝试使用一个 nullnil 的值经常会导致程序崩溃(著名的“空指针异常”或“nil 错误”)。

Swift 的 Optionals 解决了这个问题,它明确区分了“有一个值”和“没有值”两种情况。一个 Optional 类型变量要么包含一个值,要么不包含任何值 (用 nil 表示)。

声明 Optional 变量:

在类型后面加上一个问号 ? 来声明一个 Optional 类型的变量。

swift
var serverResponseCode: Int? = 404 // 可以是一个 Int 值,或者 nil
var surveyAnswer: String? // 默认值为 nil

nil:

nil 表示一个 Optional 变量不包含任何值。

swift
var website = "swift.org"
website = nil // 现在 website 没有值了

注意:nil 不能用于非 Optional 类型的变量或常量。如果你声明了一个非 Optional 的变量,它必须始终有一个非 nil 的值。

访问 Optional 的值 (解包 Unwrapping):

因为 Optional 变量可能没有值,所以你不能直接像访问普通变量那样访问它的值或属性。在安全使用 Optional 包含的值之前,你必须先解包 (unwrap) 它。Swift 提供了几种解包 Optional 的方式:

  1. 强制解包 (Forced Unwrapping): 在 Optional 变量名后面加上感叹号 !

    swift
    let possibleString: String? = "一个可选字符串"
    print(possibleString!) // 输出: 一个可选字符串

    警告: 如果你强制解包一个值为 nil 的 Optional,你的程序将会发生运行时错误并崩溃 (fatal error)。所以,强制解包非常危险,除非你百分之百确定它一定有值。 作为新手,应尽量避免使用强制解包。

  2. 可选绑定 (Optional Binding): 使用 if letwhile let 来安全地检查 Optional 是否有值,如果有,就把它绑定到一个临时的常量或变量上。

    “`swift
    var optionalName: String? = “John Appleseed”
    var greeting = “Hello!”

    if let name = optionalName { // 检查 optionalName 是否有值,如果有,将值赋给临时的 name 常量
    greeting = “Hello, (name)” // 在 if 语句块内,name 是非 Optional 的 String
    print(greeting) // 输出: Hello, John Appleseed
    } else {
    print(“optionalName 是 nil”)
    }

    // 你也可以同时解包多个 Optional
    if let firstCode = serverResponseCode, firstCode == 404 {
    print(“服务器响应错误 404”)
    }

    // 还可以使用 var 绑定
    if var editableName = optionalName {
    editableName += ” Smith”
    print(editableName) // 输出: John Appleseed Smith
    }
    “`
    可选绑定是推荐的、最安全的解包方式。

  3. 可选链 (Optional Chaining): 使用问号 ?. 来安全地调用 Optional 值上的方法、访问属性或下标。如果 Optional 为 nil,整个表达式会安全地失败,并返回 nil,而不会引起运行时错误。

    “`swift
    class Residence {
    var numberOfRooms = 1
    }

    class Person {
    var residence: Residence? // residence 是 Optional 的 Residence
    }

    let john = Person()
    // john.residence 是 nil,尝试访问 numberOfRooms 会导致错误

    // 使用可选链安全访问
    if let roomCount = john.residence?.numberOfRooms { // 如果 john.residence 非 nil,则访问 numberOfRooms
    print(“John 的住所房间数为 (roomCount)”)
    } else {
    print(“John 没有住所”) // 输出: John 没有住所
    }

    john.residence = Residence() // 现在 john 有住所了

    if let roomCount = john.residence?.numberOfRooms {
    print(“John 的住所房间数为 (roomCount)”) // 输出: John 的住所房间数为 1
    }
    ``
    可选链可以连接多个调用,如果链中的任何一个环节是
    nil,整个链就会中断并返回nil`。

  4. 空合运算符 (Nil-Coalescing Operator): 使用 ?? 运算符为一个 Optional 提供一个默认值,当 Optional 为 nil 时,就使用这个默认值。

    “`swift
    let defaultColorName = “red”
    var userProvidedColorName: String? // 可能是 nil

    let colorToUse = userProvidedColorName ?? defaultColorName // 如果 userProvidedColorName 非 nil,使用它的值;否则,使用 defaultColorName

    print(colorToUse) // 输出: red (因为 userProvidedColorName 是 nil)

    userProvidedColorName = “blue”
    let anotherColorToUse = userProvidedColorName ?? defaultColorName

    print(anotherColorToUse) // 输出: blue (因为 userProvidedColorName 非 nil)
    “`

Optionals 是 Swift 独有的重要特性,理解并正确使用它们是掌握 Swift 的关键一步。优先使用可选绑定、可选链和空合运算符进行安全解包。

12. 结构体 (Structs) 与类 (Classes) 的初步认识

结构体和类是 Swift 中用于创建自定义数据类型的基础构建块。它们都用来定义属性(存储值)和方法(提供功能)。

  • 结构体 (Struct): 使用 struct 关键字定义。
  • 类 (Class): 使用 class 关键字定义。

“`swift
// 定义一个简单的结构体
struct Point {
var x = 0.0
var y = 0.0
}

// 定义一个简单的类
class Person {
var name: String
var age: Int

// 初始化器 (Initializer),用于创建类的实例
init(name: String, age: Int) {
    self.name = name
    self.age = age
}

func sayHello() {
    print("你好,我是 \(name),今年 \(age) 岁。")
}

}

// 创建结构体实例
var point1 = Point(x: 10.0, y: 20.0)
var point2 = point1 // 将 point1 赋值给 point2

// 修改 point1 的属性
point1.x = 30.0

print(point1.x) // 30.0
print(point2.x) // 10.0 ✨ 注意这里:point2 的值没有改变!

// 创建类实例
let person1 = Person(name: “Alice”, age: 30)
let person2 = person1 // 将 person1 赋值给 person2

// 修改 person1 的属性
person1.age = 31

print(person1.age) // 31
print(person2.age) // 31 ✨ 注意这里:person2 的 age 也改变了!
“`

结构体和类的核心区别:值类型 vs. 引用类型

上面的例子揭示了结构体和类的最根本区别:

  • 结构体是值类型 (Value Types): 当你将一个结构体实例赋给另一个变量或常量,或者将其作为参数传递给函数时,实际上是复制 (Copy) 了这个结构体的所有值。每个变量/常量都拥有自己独立的数据副本。修改其中一个副本不会影响其他副本。Swift 的基本类型(Int, Double, Bool, String, Array, Dictionary, Set)也都是值类型。
  • 类是引用类型 (Reference Types): 当你将一个类实例赋给另一个变量或常量,或者将其作为参数传递给函数时,实际上是复制 (Copy) 了指向这个类实例的引用 (Reference)。多个变量/常量可能指向同一个内存中的类实例。修改其中一个变量/常量所引用的实例,会影响到所有引用同一个实例的其他变量/常量。

理解值类型和引用类型的区别对于编写正确的 Swift 代码至关重要。在实际开发中,根据你的需求(是需要独立的副本还是共享同一个实例)来选择使用结构体还是类。Swift 中结构体使用非常广泛,Apple 推荐在许多场景下优先考虑使用结构体。

结构体的初始化器 (Initializer):

结构体有一个自动生成的“逐一成员初始化器”(memberwise initializer),它允许你使用属性名来创建新的结构体实例,如 Point(x: 10.0, y: 20.0)

类的初始化器 (Initializer):

没有默认的逐一成员初始化器(除非所有属性都有默认值)。你需要自己定义 init() 方法来初始化类的实例。在 init 方法中,你必须确保类的所有存储属性都被赋初值。

结构体和类还有其他区别,比如继承(只有类支持)、类型转换、析构器(deinitializer,只有类支持)等,这些属于更高级的主题,在后续学习中会深入了解。

13. 枚举 (Enums)

枚举(Enumerations)定义了一组相关的、有共同类型的命名值。它允许你以类型安全的方式处理一组有限的选择。

定义枚举:

使用 enum 关键字定义。

“`swift
enum CompassDirection {
case north
case south
case east
case west
}

// 使用枚举
var directionToHead = CompassDirection.west
print(directionToHead) // 输出: west

// 可以简写,因为类型已经确定
directionToHead = .north
“`

枚举与 switch 语句:

枚举与 switch 语句配合使用非常强大,因为 switch 语句处理枚举时必须穷尽所有 case,这提供了编译时的安全性。

swift
switch directionToHead {
case .north:
print("Heading North")
case .south:
print("Heading South")
case .east:
print("Heading East")
case .west:
print("Heading West")
// 不需要 default,因为已经穷尽了所有可能的 case
}

关联值 (Associated Values):

枚举的每个成员可以存储一个或多个关联值,这些关联值可以是任何类型。这使得枚举成员可以携带额外的信息。

“`swift
enum Barcode {
case upc(Int, Int, Int, Int) // UPCA 条形码有四个 Int 关联值
case qrCode(String) // QRCode 条形码有一个 String 关联值
}

// 创建带有关联值的枚举实例
var productBarcode = Barcode.upc(8, 85909, 51226, 3)
productBarcode = .qrCode(“ABCDEFGHIJKLMNOP”) // 可以修改为另一个枚举成员,关联值也会随之改变

// 使用 switch 语句提取关联值
switch productBarcode {
case .upc(let numberSystem, let manufacturer, let product, let check):
print(“UPC: (numberSystem), (manufacturer), (product), (check).”)
case .qrCode(let productCode):
print(“QR code: (productCode).”)
}
// 输出: QR code: ABCDEFGHIJKLMNOP.

// 如果所有关联值都是常量或变量,可以简写
switch productBarcode {
case let .upc(numberSystem, manufacturer, product, check):
print(“UPC: (numberSystem), (manufacturer), (product), (check).”)
case let .qrCode(productCode):
print(“QR code: (productCode).”)
}
“`

原始值 (Raw Values):

枚举成员可以预设一个相同类型的默认值,称为原始值。原始值可以是字符串、字符,或者任何整数或浮点数类型。

“`swift
enum ASCIIControlCharacter: Character { // 原始值类型是 Character
case tab = “\t”
case lineFeed = “\n”
case carriageReturn = “\r”
}

print(ASCIIControlCharacter.tab.rawValue) // 输出: \t

// 如果原始值是整数或字符串,并且没有显式赋值,Swift 会自动生成
// 对于整数,会从 0 或上一个成员的值开始递增
enum Planet: Int {
case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune
}
print(Planet.earth.rawValue) // 输出: 3 (venus 是 2, earth 是 3, …)

// 对于字符串,原始值默认为成员名本身
enum Season: String {
case spring, summer, autumn, winter
}
print(Season.summer.rawValue) // 输出: summer

// 可以使用原始值初始化一个枚举实例 (结果是 Optional)
let possiblePlanet = Planet(rawValue: 3) // possiblePlanet 是 Planet.earth
print(possiblePlanet!) // 输出: earth

let anotherPossiblePlanet = Planet(rawValue: 9) // anotherPossiblePlanet 是 nil
print(anotherPossiblePlanet) // 输出: nil
“`

枚举是 Swift 中用于建模有限状态或固定选项集的强大工具。

14. 接下来的学习方向

恭喜你!你已经掌握了 Swift 编程的基础知识。这只是一个开始,Swift 还有许多更高级和更强大的特性值得学习:

  • 错误处理 (Error Handling): 如何处理程序运行时可能出现的错误(使用 do-catch, try, throws)。
  • 协议 (Protocols): 定义蓝图,让类、结构体或枚举遵循特定的行为或功能。这是 Swift 协议导向编程的核心。
  • 扩展 (Extensions): 为现有的类、结构体、枚举或协议添加新功能。
  • 泛型 (Generics): 编写可以适用于任何类型的灵活、可重用函数和类型。
  • 内存管理 (Memory Management): 了解 Swift 的 ARC (Automatic Reference Counting) 如何管理类的实例内存。
  • 并发 (Concurrency): 学习如何编写多任务程序(Swift 的 async/await)。
  • 高级运算符、下标、继承、多态等等。
  • 面向对象编程 (OOP) 和协议导向编程 (POP) 的深入理解。

学习完这些语言特性后,你就可以开始着手构建实际的应用了。根据你的兴趣,你可以选择以下方向:

  • iOS/macOS/watchOS/tvOS App 开发: 学习 SwiftUI (现代声明式 UI 框架) 或 UIKit (经典的命令式 UI 框架) 来构建用户界面。
  • 服务器端开发: 使用 Swift 并借助 Vapor 或 Kitura 等框架构建后端服务。
  • 其他领域: 探索 Swift 在命令行工具、机器学习等领域的应用。

推荐资源:

  • The Swift Programming Language (官方文档): 这是最权威、最详细的 Swift 学习资料,建议作为参考手册。
  • Apple Developer 文档: 学习 SwiftUI, UIKit 等框架的必备资源。
  • 各种在线课程平台: 如 Coursera, Udemy, B站等,有大量的 Swift 教学视频。
  • 技术博客和社区: 阅读其他开发者的经验分享,参与社区讨论。

结论

你已经迈出了 Swift 编程的第一步。Swift 是一门功能强大且不断发展的语言,学习过程需要耐心和实践。回顾本教程涵盖的基础知识,并在 Playground 中多加练习。尝试编写一些简单的小程序,例如计算器、猜数字游戏、文本处理脚本等,将学到的知识付诸实践。

编程是一项技能,需要通过不断地编写代码来磨练。不要害怕犯错,错误是学习过程的一部分。当你遇到问题时,学会查阅文档、搜索答案、请教他人。

祝你学习愉快,在 Swift 的世界里开启你的编程之旅!

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部