扬帆起航:Swift 编程入门之旅
欢迎来到 Swift 的世界!如果你渴望学习 iOS、macOS、watchOS、tvOS 甚至服务器端应用的开发,或者只是想掌握一门现代、强大且易学的编程语言,那么 Swift 是一个绝佳的选择。由苹果公司于 2014 年推出,Swift 旨在提供一种安全、快速且富有表现力的编程体验。它融合了 C 和 Objective-C 的优秀特性,同时摒弃了 C 语言的兼容性限制,带来了许多现代化的编程理念。
本文将带你从零开始,一步步踏入 Swift 的大门,详细介绍其核心概念、语法特性以及如何开始你的第一个 Swift 程序。无论你是否有编程基础,本文都力求以清晰易懂的方式为你导航。
第一章: Swift 是什么?为什么选择 Swift?
在我们深入学习语法之前,先来了解一下 Swift。
Swift 是什么?
Swift 是一种多范式、编译型编程语言,由苹果公司开发,用于构建 iOS、macOS、watchOS 和 tvOS 应用。自 Swift 3.0 起,它变得更加稳定,并且通过开源,吸引了越来越多的开发者社区参与。除了苹果平台,Swift 也可以用于构建服务器端应用(例如使用 Vapor 或 Kitura 框架)以及跨平台命令行工具。
为什么选择 Swift?
- 现代与安全: Swift 吸收了现代语言的先进思想,许多常见的编程错误(如空指针引用)在编译阶段就能被捕获,大大提高了代码的安全性。它强制要求在使用可能为 nil 的变量前进行安全处理(Optionals),避免了 Objective-C 中常见的奔溃问题。
- 快速: Swift 编译器经过优化,能够生成高性能的代码。它在很多任务上比 Objective-C 运行得更快。
- 富有表现力与易读: Swift 的语法简洁直观,更接近自然语言,使得代码更易于阅读和编写。它支持类型推断,可以减少代码冗余。
- 强大的工具支持: 结合 Xcode 开发环境,Swift 提供了强大的工具链,包括交互式的 Playgrounds(一个让你实时看到代码执行结果的环境)、先进的调试器和性能分析工具。
- 开源与社区: Swift 是开源的(swift.org),拥有一个活跃的全球社区。这促进了语言的持续发展和跨平台应用。
- 未来趋势: 苹果公司正在将越来越多的系统框架迁移到 Swift,并且新的技术(如 SwiftUI)主要或仅支持 Swift。掌握 Swift 是开发苹果平台应用的长远之计。
第二章: 环境搭建与你的第一个 Swift 程序
学习 Swift,最推荐的环境是苹果官方提供的集成开发环境(IDE)—— Xcode。
环境搭建:Xcode
- 下载 Xcode: 如果你使用的是 Mac 电脑,可以直接从 Mac App Store 免费下载 Xcode。Xcode 体积较大,下载和安装可能需要一些时间。
- 安装: 下载完成后,按照提示进行安装。
- 启动: 安装完毕后,在“应用程序”文件夹中找到并打开 Xcode。
初识 Xcode Playground
对于初学者来说,Xcode Playgrounds 是一个极好的起点。它允许你编写 Swift 代码并立即看到执行结果,无需创建一个完整的项目。
- 创建 Playground: 打开 Xcode,选择
File
->New
->Playground...
。 - 选择模板: 选择
Blank
模板,点击Next
。 - 命名和保存: 给你的 Playground 命名(例如
MyFirstSwiftPlayground
),选择保存位置,点击Create
。
Xcode 会打开一个窗口,左侧是代码编辑区,右侧是结果显示区。默认会有一行代码:
swift
import UIKit // 或 import Cocoa,取决于你选择的平台
var greeting = "Hello, playground"
这是 Swift 的基本语法。import
语句用于引入框架(这里是 UIKit 或 Cocoa,提供了图形界面等功能,对于纯语法学习可以忽略或删除),var
用于声明一个变量,=
用于赋值,"Hello, playground"
是一个字符串字面量。
右侧的结果区会显示 greeting
变量的值。如果你在代码区写下:
swift
print(greeting)
在结果区下方或右侧会看到输出 Hello, playground
。print()
是一个常用的函数,用于在控制台输出信息。
你的第一个 Swift 程序:Hello, World!
传统上,学习任何编程语言的第一步都是编写一个输出“Hello, World!”的程序。在 Swift Playground 中,这非常简单:
swift
print("Hello, World!")
就是这样!在结果区你会看到输出 Hello, World!
。你已经成功写下了你的第一个 Swift 程序。
第三章: Swift 基础:常量、变量与数据类型
编程的核心是对数据的操作。在 Swift 中,数据存储在常量或变量中,并且有不同的类型。
常量与变量
Swift 提供了两种存储值的命名容器:常量(Constants)和变量(Variables)。
-
常量 (let): 用
let
关键字声明。一旦赋值,其值就不能再改变。
swift
let maxLoginAttempts = 10 // 登录尝试的最大次数是固定的
// maxLoginAttempts = 5 // 错误!常量不能重新赋值
使用常量是 Swift 推荐的做法,因为它能提高代码的安全性,防止意外修改。只有当你确定一个值会在程序运行时改变时,才使用变量。 -
变量 (var): 用
var
关键字声明。其值可以在后续代码中改变。
swift
var currentLoginAttempt = 0 // 当前登录尝试次数会随着用户输入而改变
currentLoginAttempt = currentLoginAttempt + 1 // 现在 currentLoginAttempt 的值变成 1
类型推断 (Type Inference)
Swift 是一门强类型语言,意味着每个常量或变量都必须有一个明确的类型。然而,你通常不需要显式地指定类型,因为 Swift 编译器有强大的类型推断能力。它会根据你赋给常量或变量的初始值来自动推断其类型。
swift
let meaningOfLife = 42 // Swift 推断 meaningOfLife 是 Int 类型 (整数)
let pi = 3.14159 // Swift 推断 pi 是 Double 类型 (双精度浮点数)
let name = "Alice" // Swift 推断 name 是 String 类型 (字符串)
显式类型标注 (Type Annotation)
虽然 Swift 可以推断类型,但你也可以选择显式地标注类型。这在某些情况下很有用,比如当你声明常量或变量时不想立即赋初值,或者当你需要指定一个与推断类型不同的类型时。显式标注使用冒号 :
后跟类型名称。
“`swift
var welcomeMessage: String // 声明一个 String 类型的变量,但暂时不赋值
welcomeMessage = “Hello!” // 现在可以赋一个 String 类型的值
var red, green, blue: Double // 一行声明多个相同类型的变量
“`
基本数据类型 (Basic Data Types)
Swift 提供了多种内置数据类型来处理不同种类的数据。
-
整型 (Integers): 用于存储整数。Swift 提供了
Int
(根据平台位数,通常是 Int64 或 Int32) 和UInt
(无符号整数) 等。还有定长的整型,如Int8
,Int16
,Int32
,Int64
和对应的无符号类型。
swift
let age: Int = 30
let bigNumber: Int64 = 1_000_000_000 // 下划线可以提高数字的可读性 -
浮点型 (Floating-Point Numbers): 用于存储带小数的数字。Swift 提供了
Double
(64位,精度更高,默认类型) 和Float
(32位)。
swift
let temperature: Double = 25.5
let price: Float = 9.99
注意: 不同数字类型之间的转换需要显式进行,避免数据丢失或错误。
swift
let integerPrice = Int(price) // Float 转 Int,会截断小数部分
let doubleAge = Double(age) // Int 转 Double -
布尔型 (Booleans): 用于存储逻辑值,只有两个可能的值:
true
和false
。通常用于条件判断。
swift
let isLoggedId: Bool = true
let hasPermission = false -
字符串 (Strings): 用于存储文本。字符串是值的类型(Value Type),不是引用类型。
swift
let greeting = "Hello!"
let welcome = "Welcome to Swift."
let combined = greeting + " " + welcome // 字符串拼接
Swift 的字符串支持 Unicode,可以包含几乎任何语言的字符和表情符号。字符串插值 (String Interpolation) 是将常量、变量、字面量或表达式的值插入到字符串字面量中的方法。
swift
let user = "Alice"
let message = "Hello, \(user)! Your age is \(age)." // 使用 \(...) 语法
print(message) // 输出: Hello, Alice! Your age is 30. -
字符 (Characters): 用于存储单个字符。
swift
let exclamationMark: Character = "!"
第四章: 操作符 (Operators)
操作符是特殊的符号或短语,用于检查、改变或组合值。Swift 支持多种操作符。
-
算术操作符 (Arithmetic Operators): 用于执行基本的数学运算。
swift
let sum = 10 + 5 // 加法
let difference = 20 - 8 // 减法
let product = 4 * 6 // 乘法
let quotient = 10 / 2 // 除法
let remainder = 10 % 3 // 求余 (结果是 1) -
比较操作符 (Comparison Operators): 用于比较两个值,结果是布尔值 (
true
或false
)。
swift
10 == 10 // 等于
5 != 8 // 不等于
7 > 3 // 大于
4 < 9 // 小于
6 >= 6 // 大于等于
2 <= 5 // 小于等于 -
逻辑操作符 (Logical Operators): 用于组合或修改布尔逻辑值。
“`swift
let isSunny = true
let isWarm = false!isSunny // 逻辑非 (NOT),结果是 false
isSunny && isWarm // 逻辑与 (AND),如果两个都为 true 结果才为 true,这里是 false
isSunny || isWarm // 逻辑或 (OR),如果任意一个为 true 结果就为 true,这里是 true
“` -
赋值操作符 (Assignment Operator): 用于给常量或变量赋值。
swift
var x = 10
x = 20 // 赋值 -
复合赋值操作符 (Compound Assignment Operators): 将赋值操作符与算术操作符结合。
swift
var y = 10
y += 5 // 等同于 y = y + 5,现在 y 是 15
y -= 3 // 等同于 y = y - 3,现在 y 是 12
// 同样适用于 *=, /=, %= 等
第五章: 控制流 (Control Flow)
控制流语句用于控制代码的执行顺序,实现条件判断、循环等。
条件语句 (Conditional Statements)
-
if 语句: 根据条件执行不同的代码块。
swift
let score = 85
if score >= 60 {
print("及格")
} else {
print("不及格")
} -
if-else if-else 语句: 处理多个互斥的条件。
swift
let grade = 75
if grade >= 90 {
print("优秀")
} else if grade >= 80 {
print("良好")
} else if grade >= 60 {
print("及格")
} else {
print("不及格")
} -
switch 语句: 根据一个值匹配不同的模式。在 Swift 中,switch 语句非常强大,并且每个 case 后面不需要写
break
(默认不会fallthrough)。
swift
let dayOfWeek = "Monday"
switch dayOfWeek {
case "Monday":
print("周一")
case "Tuesday":
print("周二")
case "Wednesday", "Thursday", "Friday": // 可以匹配多个值
print("工作日")
default: // 必须包含 default 或覆盖所有可能情况
print("周末")
}
Switch 语句还可以进行值绑定(Value Binding)和模式匹配,这使得它比许多其他语言的 switch 更灵活。
循环语句 (Loop Statements)
-
for-in 循环: 用于遍历序列,如数字范围、数组、字符串的字符等。
“`swift
// 遍历数字范围 (包含 upper bound)
for i in 1…5 {
print(i) // 输出 1, 2, 3, 4, 5
}// 遍历数字范围 (不包含 upper bound)
for i in 1..<5 {
print(i) // 输出 1, 2, 3, 4
}// 遍历数组
let fruits = [“Apple”, “Banana”, “Cherry”]
for fruit in fruits {
print(“I like (fruit)”)
}// 遍历字符串的字符
let word = “Swift”
for character in word {
print(character)
}// 如果不需要循环变量,可以使用下划线
_
for _ in 0..<3 {
print(“Repeat me”) // 会打印三次
}
“` -
while 循环: 当条件为真时重复执行代码块。
swift
var count = 0
while count < 5 {
print("Count is \(count)")
count = count + 1 // 或者 count += 1
} -
repeat-while 循环: 先执行一次代码块,然后当条件为真时重复执行。至少执行一次。
swift
var i = 0
repeat {
print("Executing at least once. i is \(i)")
i += 1
} while i < 0 // 条件为假,但代码块已执行一次
第六章: 集合类型 (Collection Types)
Swift 提供了三种主要的集合类型来存储多个值:数组 (Arrays)、集合 (Sets) 和字典 (Dictionaries)。它们都是强类型的,意味着你存储的数据类型必须一致。
-
数组 (Arrays): 有序的值集合,同一个值可以出现多次。
“`swift
// 声明并初始化一个存储 String 的数组
var shoppingList: [String] = [“Eggs”, “Milk”]// Swift 可以推断类型
var otherShoppingList = [“Eggs”, “Milk”] // 推断为 [String]// 访问元素 (通过索引,从 0 开始)
print(shoppingList[0]) // 输出: Eggs// 修改元素
shoppingList[0] = “Six eggs” // 修改第一个元素// 添加元素
shoppingList.append(“Flour”) // 在末尾添加
shoppingList.insert(“Cheese”, at: 0) // 在指定位置插入// 移除元素
shoppingList.remove(at: 1) // 移除索引为 1 的元素 (Milk)
shoppingList.removeLast() // 移除最后一个元素 (Flour)// 遍历数组
for item in shoppingList {
print(item)
}// 获取数组大小
print(“The shopping list contains (shoppingList.count) items.”)// 检查是否为空
if shoppingList.isEmpty {
print(“The shopping list is empty.”)
}
“` -
集合 (Sets): 无序的唯一值集合。同一个值不能出现多次。当你需要存储一组唯一且顺序不重要的值时使用。
“`swift
// 声明并初始化一个存储 String 的集合
var favoriteGenres: Set= [“Rock”, “Classical”, “Hip hop”] // Swift 可以推断类型 (需要显式标注类型,因为数组和集合的字面量语法相似)
// var otherGenres: Set = [“Rock”, “Classical”, “Hip hop”] // 这样也可以// 插入元素 (如果元素已存在,不会有任何改变)
favoriteGenres.insert(“Jazz”)// 移除元素 (如果元素存在则移除并返回,否则返回 nil)
if let removedGenre = favoriteGenres.remove(“Rock”) {
print(“(removedGenre) was removed.”)
} else {
print(“Rock is not in the set.”)
}// 检查是否包含特定元素
if favoriteGenres.contains(“Jazz”) {
print(“I’m a jazz fan.”)
}// 遍历集合 (无序)
for genre in favoriteGenres {
print(genre)
}// 集合操作 (交集、并集、差集等)
let oddDigits: Set = [1, 3, 5, 7, 9]
let evenDigits: Set = [0, 2, 4, 6, 8]
let primeDigits: Set = [2, 3, 5, 7]oddDigits.union(evenDigits).sorted() // 并集: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
oddDigits.intersection(evenDigits).sorted() // 交集: []
oddDigits.subtracting(primeDigits).sorted() // 差集: [1, 9]
oddDigits.symmetricDifference(primeDigits).sorted() // 对称差集: [1, 2, 9]
“` -
字典 (Dictionaries): 无序的键值对集合。每个键都是唯一的,通过键可以快速访问对应的值。
“`swift
// 声明并初始化一个存储 String 键和 String 值的字典
var namesOfIntegers: [Int: String] = [:] // 空字典
namesOfIntegers[0] = “zero” // 添加或修改键值对
namesOfIntegers[1] = “one”// Swift 可以推断类型
var airports = [“YYZ”: “Toronto Pearson”, “DUB”: “Dublin”] // 推断为 [String: String]// 访问值 (通过键,返回一个可选类型的值)
print(airports[“YYZ”]) // 输出: Optional(“Toronto Pearson”)// 修改值
airports[“YYZ”] = “Toronto Pearson International”// 添加新键值对
airports[“LHR”] = “London Heathrow”// 移除键值对
airports[“DUB”] = nil // 将值设为 nil 即可移除
if let removedValue = airports.removeValue(forKey: “LHR”) { // 或者使用 removeValue(forKey:)
print(“Removed (removedValue).”)
}// 遍历字典 (键和值是无序的)
for (airportCode, airportName) in airports {
print(“(airportCode): (airportName)”)
}// 遍历键或值
for airportCode in airports.keys {
print(“Code: (airportCode)”)
}
for airportName in airports.values {
print(“Name: (airportName)”)
}// 获取字典大小
print(“The airports dictionary contains (airports.count) items.”)
“`
第七章: 函数 (Functions)
函数是执行特定任务的独立代码块。定义函数可以重用代码,提高程序的可维护性。
定义和调用函数
使用 func
关键字定义函数。函数可以有参数和返回值。
“`swift
// 无参数,无返回值
func greet() {
print(“Hello!”)
}
greet() // 调用函数
// 有参数,无返回值
func greet(person name: String) { // 参数标签 person,参数名 name
print(“Hello, (name)!”)
}
greet(person: “Alice”) // 调用函数时使用参数标签
// 默认情况下,第一个参数没有参数标签,后续参数有标签
func sayHello(to person: String, and anotherPerson: String) {
print(“Hello (person) and (anotherPerson)!”)
}
sayHello(to: “Bob”, and: “Charlie”)
// 可以使用 _
忽略参数标签
func printNumber(_ number: Int) {
print(“The number is (number)”)
}
printNumber(10) // 调用时不需要标签
// 有参数,有返回值
func addTwoNumbers(a: Int, b: Int) -> Int { // -> 表示返回值类型
return a + b
}
let sumResult = addTwoNumbers(a: 5, b: 3) // sumResult 为 8
// 多返回值 (使用元组 Tuple)
func minMax(array: [Int]) -> (min: Int, max: Int)? { // 返回一个可选元组
if array.isEmpty { return nil } // 数组为空,返回 nil
var currentMin = array[0]
var currentMax = array[0]
for value in array[1..<array.count] {
if value < currentMin {
currentMin = value
} else if value > currentMax {
currentMax = value
}
}
return (currentMin, currentMax) // 返回一个元组
}
let numbers = [8, -6, 2, 109, 3, 71]
if let bounds = minMax(array: numbers) { // 使用可选绑定解包返回值
print(“min is (bounds.min) and max is (bounds.max)”)
}
“`
第八章: 可选类型 (Optionals)
可选类型是 Swift 中一个非常重要的概念,用于处理值可能缺失的情况。一个可选类型要么包含一个值,要么不包含任何值 (表示为 nil
)。这解决了其他语言中常见的空指针异常问题。
可选类型用在类型后面加上问号 ?
来表示。
“`swift
let possibleNumber = “123”
let convertedNumber = Int(possibleNumber) // convertedNumber 是一个 Int? 类型,它可能包含数字 123,也可能因为字符串无法转换为整数而为 nil。
let userInput = “hello”
let anotherNumber = Int(userInput) // anotherNumber 是一个 Int? 类型,值为 nil
“`
nil
nil
表示可选类型变量或常量不包含任何值。nil
不能用于非可选类型的常量或变量。
swift
var serverResponseCode: Int? = 404 // 可选 Int 类型,包含值 404
serverResponseCode = nil // 现在它不包含任何值
// var mustHaveValue: Int = nil // 错误!非可选类型不能设为 nil
强制解包 (Forced Unwrapping)
如果你确定一个可选类型一定包含值,可以使用感叹号 !
进行强制解包。但如果它实际上是 nil
,程序就会崩溃!因此,强制解包非常危险,应尽量避免。
swift
// 假设你知道 convertedNumber 一定有值 (仅为示例,实际代码要谨慎)
print(convertedNumber!) // 输出: 123
// 如果 convertedNumber 是 nil,这行代码会引发运行时错误 (崩溃)
可选绑定 (Optional Binding)
可选绑定是安全地检查可选类型是否包含值,并在有值时将其绑定到一个临时常量或变量。使用 if let
或 guard let
语法。
-
if let: 如果可选类型有值,则将该值赋给一个临时常量或变量,然后执行
if
后面的代码块。
swift
let possibleString: String? = "An optional string."
if let actualString = possibleString { // 如果 possibleString 有值,将其赋给 actualString
print("The string has a value of \"\(actualString)\"")
} else {
print("The string is nil.")
}
// actualString 只能在 if 块内使用
你可以在一个if let
语句中绑定多个可选类型:
swift
if let firstNumber = Int("4"), let secondNumber = Int("42"), firstNumber < secondNumber {
print("\(firstNumber) < \(secondNumber)") // 输出: 4 < 42
} -
guard let: 常用于函数中,检查条件是否满足。如果可选类型有值,将其绑定到临时常量或变量,然后继续执行
guard
语句之后的代码;如果为nil
,则执行else
块中的代码,通常用于退出当前作用域(如使用return
,break
,continue
或throw
)。这有助于避免“厄运金字塔”(Pyramid of Doom) 嵌套。
“`swift
func greet(person: [String: String]) {
guard let name = person[“name”] else { // 如果 person 字典中没有 “name” 键,或者对应值为 nil
print(“I don’t know your name.”)
return // 退出函数
}
guard let location = person[“location”] else { // 如果没有 “location” 键或值为 nil
print(“Hello (name)!”)
return // 退出函数
}
print(“Hello (name) from (location)!”) // 如果两个可选绑定都成功,继续执行
}greet(person: [“name”: “John”]) // 输出: Hello John!
greet(person: [“name”: “Jane”, “location”: “Cupertino”]) // 输出: Hello Jane from Cupertino!
greet(person: [:]) // 输出: I don’t know your name.
``
guard let
通过绑定的常量/变量 (
name,
location) 在
guard语句**之后**的整个作用域内都可以使用,这是与
if let` 的主要区别。
隐式解包可选类型 (Implicitly Unwrapped Optionals)
用在类型后面加上感叹号 !
来表示。它看起来像一个可选类型,但当你访问它时,Swift 会自动强制解包。如果你确定一个变量在第一次赋值后总是会有值,并且在后续使用前不会变成 nil
,可以使用它。这通常用于初始化 IBOutlet 属性。如果在使用它时它变成了 nil
,仍然会引发运行时错误。
“`swift
var myString: String! = “Hello” // 隐式解包可选 String
let newString: String = myString // 直接使用,Swift 自动解包
print(newString) // 输出: Hello
myString = nil
// print(myString) // 这行代码会崩溃,因为 myString 变成了 nil 但被隐式解包
“`
出于安全考虑,除非有明确理由(如 IBOutlet),否则应尽量使用常规可选类型和可选绑定。
Nil Coalescing Operator (??)
??
操作符提供了一个默认值,当可选类型为 nil
时使用该默认值。
“`swift
let defaultColorName = “red”
var userDefinedColorName: String? // 默认为 nil
var colorNameToUse = userDefinedColorName ?? defaultColorName // userDefinedColorName 是 nil,所以 colorNameToUse 是 “red”
userDefinedColorName = “green”
colorNameToUse = userDefinedColorName ?? defaultColorName // userDefinedColorName 有值,所以 colorNameToUse 是 “green”
“`
第九章: 结构体与类 (Structs and Classes)
结构体 (Structs) 和类 (Classes) 是构建复杂数据类型的基础。它们都可以定义属性(Properties)来存储值,以及方法(Methods)来提供功能。它们之间的主要区别在于它们是值类型还是引用类型。
-
结构体 (Structs): 值类型 (Value Types)。当你赋值或传递一个结构体实例时,会复制其所有内容。
“`swift
struct Point {
var x = 0.0
var y = 0.0
}var p1 = Point(x: 1.0, y: 2.0)
var p2 = p1 // p2 是 p1 的一个拷贝
p2.x = 3.0 // 修改 p2 不会影响 p1print(“p1 is ((p1.x), (p1.y))”) // 输出: p1 is (1.0, 2.0)
print(“p2 is ((p2.x), (p2.y))”) // 输出: p2 is (3.0, 2.0)
“`
Swift 中的许多基本类型(如 Int, Double, String, Array, Dictionary, Set)都是结构体。 -
类 (Classes): 引用类型 (Reference Types)。当你赋值或传递一个类实例时,传递的是对同一个实例的引用。
“`swift
class Person {
var name: String
var age: Intinit(name: String, age: Int) { // 初始化方法 self.name = name self.age = age } func sayHello() { print("Hello, my name is \(name) and I am \(age) years old.") }
}
var person1 = Person(name: “Alice”, age: 30)
var person2 = person1 // person2 引用的是 person1 同一个实例
person2.age = 31 // 修改 person2 也会影响 person1print(“person1’s age is (person1.age)”) // 输出: person1’s age is 31
print(“person2’s age is (person2.age)”) // 输出: person2’s age is 31person1.sayHello() // 调用方法
“`
类支持继承(Inheritance),一个类可以继承另一个类的特性。结构体不支持继承。
何时使用结构体,何时使用类?
Swift 官方推荐在多数情况下优先使用结构体,因为值类型更易于理解和推理,可以避免引用类型可能导致的意外副作用。当你需要以下特性时,考虑使用类:
* 需要继承。
* 需要引用计数来管理内存。
* 需要与 Objective-C 代码互操作。
* 当对象的身份很重要,并且你希望多个引用指向同一个实例时。
第十章: 枚举 (Enumerations)
枚举(Enums)定义了一组相关的可能值。它们在处理有限、离散的数据集合时非常有用。
“`swift
// 定义一个简单的枚举
enum CompassPoint {
case north
case south
case east
case west
}
var directionToHead = CompassPoint.west
directionToHead = .north // 一旦变量声明为特定的枚举类型,可以简写
// 使用 switch 语句匹配枚举值
switch directionToHead {
case .north:
print(“Heading north.”)
case .south:
print(“Heading south.”)
case .east:
print(“Heading east.”)
case .west:
print(“Heading west.”)
}
// 枚举的关联值 (Associated Values)
// 可以为枚举成员关联不同类型的值
enum Barcode {
case upc(Int, Int, Int, Int) // UPC 条形码,关联四个 Int 值
case qrCode(String) // QR 码,关联一个 String 值
}
var productBarcode = Barcode.upc(8, 85909, 51226, 3)
productBarcode = .qrCode(“ABCDEFGHIJKLMNOP”) // 可以改变关联值
switch productBarcode {
case .upc(let numberSystem, let manufacturer, let product, let check):
print(“UPC: (numberSystem), (manufacturer), (product), (check).”)
case .qrCode(let productCode): // 可以在 case 后面直接解包关联值
print(“QR code: (productCode).”)
}
// 枚举的原始值 (Raw Values)
// 可以为枚举成员指定相同类型的默认值(如整数、字符串)
enum Planet: Int {
case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune // 从 1 开始,后续自动递增
}
let earthOrder = Planet.earth.rawValue // 获取原始值,结果是 3
// 通过原始值初始化枚举 (返回可选类型,因为原始值可能不存在对应的枚举成员)
if let somePlanet = Planet(rawValue: 7) {
switch somePlanet {
case .earth:
print(“It’s Earth.”)
default:
print(“It’s not Earth.”)
}
} else {
print(“There is no planet at raw value 7.”) // 7 对应 Uranus
}
“`
第十一章: 协议 (Protocols)
协议(Protocols)定义了一组方法、属性或其他要求的蓝图(blueprint)。类、结构体或枚举可以采纳(adopt)一个或多个协议,并提供这些要求的实现。协议有点像其他语言中的接口(Interfaces)。
“`swift
// 定义一个协议
protocol FullyNamed {
var fullName: String { get } // 要求实现一个只读的 fullName 属性
func sayFullName() // 要求实现一个 sayFullName 方法
}
// 让一个结构体采纳并实现协议
struct Person: FullyNamed {
var fullName: String // 实现 fullName 属性
// init 方法是必要的,因为结构体必须初始化所有属性
init(fullName: String) {
self.fullName = fullName
}
func sayFullName() { // 实现 sayFullName 方法
print("My full name is \(fullName).")
}
}
// 让一个类采纳并实现协议
class Dog: FullyNamed {
var fullName: String // 实现 fullName 属性
var breed: String
init(fullName: String, breed: String) {
self.fullName = fullName
self.breed = breed
}
func sayFullName() { // 实现 sayFullName 方法
print("Woof! My name is \(fullName).")
}
}
let john = Person(fullName: “John Appleseed”)
john.sayFullName() // 输出: My full name is John Appleseed.
let fluffy = Dog(fullName: “Fluffy”, breed: “Poodle”)
fluffy.sayFullName() // 输出: Woof! My name is Fluffy.
// 可以将遵循协议的类型作为函数参数或集合元素,实现多态
let namedItems: [FullyNamed] = [john, fluffy]
for item in namedItems {
item.sayFullName() // 调用协议方法,具体行为取决于实际类型
}
“`
协议是 Swift 中实现多态性和构建灵活代码结构的关键。
第十二章: 扩展 (Extensions)
扩展(Extensions)允许你为一个已存在的类、结构体、枚举或协议类型添加新的功能,而无需访问其原始源代码。
“`swift
// 扩展 Double 类型,添加一个属性和方法
extension Double {
var km: Double { return self * 1_000.0 } // 添加一个计算属性
var m: Double { return self }
var cm: Double { return self / 100.0 }
var mm: Double { return self / 1_000.0 }
var ft: Double { return self / 3.28084 }
func printMeasurement() { // 添加一个方法
print("\(self) meters")
}
}
let oneInch = 25.4.mm // 使用扩展添加的属性
print(“One inch is (oneInch) meters”) // 输出: One inch is 0.0254 meters
let threeFeet = 3.0.ft
threeFeet.printMeasurement() // 输出: 0.9143999999999999 meters (使用扩展添加的方法)
// 扩展 Int 类型,添加方法
extension Int {
func repetitions(task: () -> Void) { // 接受一个无参数无返回值的闭包作为参数
for _ in 0..<self {
task() // 执行闭包
}
}
}
3.repetitions { // 调用扩展方法,并传入一个尾随闭包
print(“Hello!”) // 输出三次 Hello!
}
“`
扩展可以添加计算属性、实例方法、类型方法、初始化器、下标、嵌套类型和协议采纳。但不能添加存储属性。
第十三章: 并发 (Concurrency)
现代应用通常需要同时处理多个任务,比如下载数据时保持用户界面响应。这涉及到并发编程。Swift 在不断演进其并发模型。
早期 Swift 主要依赖 Grand Central Dispatch (GCD) 和 Operation Queues 来处理并发。Swift 5.5 引入了基于 async/await
的结构化并发模型,这是一种更现代、更安全的方式来编写异步代码。
- async 函数: 用
async
标记的函数表示它是异步的,可能会在某个点挂起执行,等待异步操作完成。 - await 调用: 在调用
async
函数时,使用await
关键字表示当前任务会在此处暂停,直到被调用的异步函数完成并返回结果。这不会阻塞整个线程,而是让出执行权。
“`swift
// 示例:模拟一个异步下载数据的函数
func downloadData(from url: String) async -> Data? {
print(“开始下载数据…”)
// 实际下载代码… 假设这里是一个耗时操作
try? await Task.sleep(nanoseconds: 2_000_000_000) // 模拟网络延迟 2 秒
print(“下载完成.”)
return Data() // 假设下载成功并返回一个 Data 对象
}
// 调用异步函数需要在异步上下文 (如另一个 async 函数或 Task) 中
func processDownload() async {
print(“准备处理下载…”)
if let data = await downloadData(from: “https://example.com/data”) { // 使用 await 调用异步函数
print(“成功获取到数据 ((data.count) 字节).”)
// 处理数据…
} else {
print(“下载失败.”)
}
print(“处理下载结束.”)
}
// 在非异步上下文 (如主线程) 中启动异步任务
Task {
await processDownload()
}
print(“任务已启动…”) // 这行代码会先执行,因为 processDownload 是异步的
// 完整的输出顺序大致是:
// 任务已启动…
// 准备处理下载…
// 开始下载数据…
// (等待 2 秒…)
// 下载完成.
// 成功获取到数据 (0 字节).
// 处理下载结束.
``
async/await` 的结构化并发是 Swift 未来的方向,它提供了更好的可读性、安全性和错误处理。
基于
第十四章: 何去何从?后续学习建议
恭喜你!你已经掌握了 Swift 的核心语法和基本概念。这只是冰山一角,但你已经具备了进一步深入学习的基础。接下来你可以:
- 深入学习更高级的 Swift 特性: 错误处理、泛型、协议导向编程、高级集合操作、内存管理(ARC)、属性包装器、结果类型(Result)等。
- 学习苹果平台的 UI 开发:
- SwiftUI: 苹果最新的声明式 UI 框架,跨平台(iOS, macOS, watchOS, tvOS),使用 Swift 编写。更现代、更易于上手。
- UIKit (iOS/tvOS) / AppKit (macOS): 苹果传统的命令式 UI 框架,依然广泛使用。
- 学习特定领域的开发: Core Data (数据持久化)、Core Animation (动画)、Combine (响应式编程)、Machine Learning (机器学习) 等。
- 学习服务器端 Swift: 了解 Vapor、Kitura 等框架,使用 Swift 构建后端服务。
- 练习: 最重要的是通过编写代码来巩固所学。从小型项目开始,例如一个计算器应用、一个待办事项列表、一个简单的游戏等。
- 阅读官方文档: Swift 语言指南 (The Swift Programming Language) 是最权威、最详细的资源。虽然一开始可能有些枯燥,但它是查找特定语法细节和深入理解概念的最佳途径。
- 参与社区: 访问 Swift 论坛、Stack Overflow、GitHub 等,阅读其他人的代码,提问和回答问题。
- 在线课程和教程: 有大量优秀的在线平台(如 Stanford 的 CS193p 课程、Udemy、Coursera、B站等)提供 Swift 和苹果开发课程。
总结
Swift 是一门充满活力、现代且功能强大的编程语言。它通过强调安全性、速度和易读性,使得开发苹果平台的应用变得更加愉悦和高效。从常量变量到可选类型,从结构体类到协议扩展,你已经触及了 Swift 的核心。并发模型 async/await
的引入更是让异步编程变得前所未有的清晰。
编程是一项需要不断学习和实践的技能。这篇入门文章为你奠定了基础,但真正的学习始于你写下第一行代码、遇到第一个错误、解决第一个难题。
勇敢地去尝试吧!启动 Xcode,打开 Playgrounds,或者创建一个新的项目。将你学到的知识付诸实践,不断探索 Swift 的无限可能。祝你在 Swift 的世界里扬帆远航,创造出令人惊叹的应用!