Swift 快速入门教程:开启你的 Apple 生态开发之旅
欢迎来到 Swift 的世界!Swift 是由 Apple 公司于 2014 年推出的一种现代化、强大且直观的编程语言。它被设计用于开发 iOS、macOS、watchOS、tvOS 以及 Linux 应用程序。Swift 结合了 C 和 Objective-C 的优点,同时摒弃了它们的许多限制,并引入了现代编程语言的特性,如类型安全、内存安全、高性能和简洁的语法。
本教程旨在为初学者提供一个全面的 Swift 基础知识概览,帮助你快速上手,并为后续深入学习和实际项目开发打下坚实的基础。我们将从环境搭建开始,逐步深入变量、常量、数据类型、控制流、函数、集合、可选类型、结构体与类等核心概念。
目标读者: 本教程适合对编程有初步了解,或者希望从其他语言(如 Python、Java、C# 等)转向 Swift 的开发者。即使你是编程新手,只要跟着步骤耐心学习,也能掌握 Swift 的基本用法。
预计学习时间: 完整阅读和实践本教程大约需要 3-5 小时。
1. 准备工作:搭建开发环境
要开始编写和运行 Swift 代码,你需要一个合适的开发环境。
-
macOS 用户:
- Xcode: 这是 Apple 官方的集成开发环境(IDE),包含了编写、编译、调试和发布 Apple 平台应用所需的一切工具,包括 Swift 编译器和 SDK。你可以从 Mac App Store 免费下载安装 Xcode。
- Playgrounds: Xcode 内置了一个名为 Playgrounds 的交互式环境,非常适合学习 Swift 语法和试验代码片段,无需创建完整的项目。启动 Xcode 后,选择 “File” > “New” > “Playground…” 即可创建一个 Playground 文件。这是我们入门学习的首选工具。
-
Linux 用户:
- 你可以从 Swift.org 下载适用于 Ubuntu 等发行版的 Swift 工具链。安装后,你可以在终端中使用
swift
命令来编译和运行 Swift 代码,或者使用swift run
命令运行 Swift Package Manager 管理的项目。你也可以使用 VS Code 等编辑器配合 Swift 插件进行开发。
- 你可以从 Swift.org 下载适用于 Ubuntu 等发行版的 Swift 工具链。安装后,你可以在终端中使用
-
Windows 用户:
- 官方并未直接支持 Windows。但可以通过 Windows Subsystem for Linux (WSL) 运行 Linux 版 Swift 工具链,或者使用一些在线 Swift 编辑器和编译器(如 Replit、Online Swift Playground 等)进行学习。
在本教程中,我们主要假设你使用 macOS 上的 Xcode Playgrounds 进行学习。
创建一个 Playground:
1. 打开 Xcode。
2. 在欢迎窗口选择 “Get started with a playground”,或者通过菜单 “File” > “New” > “Playground…”。
3. 选择 “iOS” (或 macOS) 平台下的 “Blank” 模板。
4. 给你的 Playground 文件命名(例如 “SwiftBasics”),选择保存位置,然后点击 “Create”。
你将看到一个编辑区域,左侧是代码输入区,右侧是实时结果显示区。现在,你可以开始编写你的第一行 Swift 代码了!
2. Swift 基础语法
2.1 第一个 Swift 程序:Hello, World!
在 Playground 中,删除默认的代码,输入以下内容:
swift
print("Hello, Swift!")
在右侧的结果区域,你应该能看到输出了 Hello, Swift!
。print()
是一个内置函数,用于将内容输出到控制台。
注意: Swift 语句末尾通常不需要分号 (;
),除非你想在同一行写多个语句。
2.2 注释
注释用于解释代码,编译器会忽略它们。
- 单行注释:以
//
开始,直到行尾。
swift
// 这是一个单行注释
print("Hello again!") // 也可以在代码后面添加注释 - 多行注释:以
/*
开始,以*/
结束,可以跨越多行。
swift
/*
这是一个
多行注释。
*/
print("Learning Swift is fun!")
2.3 常量与变量
在 Swift 中,你需要在使用数据之前声明它。数据存储在常量或变量中。
-
常量 (Constants): 使用
let
关键字声明。常量的值一旦设定后就不能再改变。推荐优先使用常量,以增加代码的安全性和可预测性。
swift
let maximumLoginAttempts = 10 // 登录尝试最大次数,设定后不变
let welcomeMessage = "Welcome!"
// maximumLoginAttempts = 11 // 这行会报错:Cannot assign to value: 'maximumLoginAttempts' is a 'let' constant -
变量 (Variables): 使用
var
关键字声明。变量的值在声明后可以被修改。
“`swift
var currentLoginAttempt = 0 // 当前登录尝试次数,可以变化
currentLoginAttempt = 1
currentLoginAttempt += 1 // 等同于 currentLoginAttempt = currentLoginAttempt + 1var userGreeting = “Hello”
userGreeting = “Hi there”
“`
2.4 类型注解与类型推断
Swift 是一种类型安全 (Type-Safe) 的语言。这意味着每个变量或常量都有一个明确的类型(如整数、字符串、布尔值等),编译器会在编译时检查类型匹配,防止类型错误。
-
类型推断 (Type Inference): 大多数情况下,你不需要显式指定类型。Swift 编译器可以根据你赋的初始值自动推断出常量或变量的类型。
swift
let pi = 3.14159 // Swift 推断 pi 为 Double 类型
let message = "Swift" // Swift 推断 message 为 String 类型
var count = 0 // Swift 推断 count 为 Int 类型 -
类型注解 (Type Annotation): 如果需要,或者为了代码更清晰,你可以显式地指定类型,使用冒号
:
后面跟类型名称。
“`swift
let explicitDouble: Double = 70.0
var playerName: String = “Alice”
var score: Int = 100
let isGameOver: Bool = false // 布尔类型// 当你声明一个变量但没有立刻赋初始值时,必须使用类型注解
var environment: String
environment = “Development”
// print(environment) // 必须先赋值才能使用
“`
3. 基本数据类型
Swift 提供了多种基本数据类型来表示不同种类的数据。
-
整数 (Integers):
Int
用于表示整数。它的大小通常与平台的原生字长相同(在 32 位平台是Int32
,在 64 位平台是Int64
)。Swift 还提供了特定位数的整数类型,如Int8
,Int16
,Int32
,Int64
和对应的无符号版本UInt8
,UInt16
,UInt32
,UInt64
。
swift
let age: Int = 30
let year = 2024 // 推断为 Int
let veryLargeNumber: Int64 = 9_223_372_036_854_775_807 // 可以用下划线增加可读性 -
浮点数 (Floating-Point Numbers): 用于表示带有小数的数字。
Double
: 表示 64 位浮点数,精度更高,是 Swift 推断浮点数的默认类型。推荐在大多数情况下使用Double
。Float
: 表示 32 位浮点数,精度较低。
swift
let piValue: Double = 3.1415926535
let approximatePi: Float = 3.14
let gravity = 9.8 // 推断为 Double
注意: Swift 不允许Int
和Double
/Float
直接混合运算,需要显式转换。
swift
let three = 3
let pointOneFour = 0.14
// let result = three + pointOneFour // 错误!
let result = Double(three) + pointOneFour // 正确:将 Int 转换为 Double
print(result) // 输出 3.14
-
布尔值 (Booleans):
Bool
只有两个可能的值:true
和false
。常用于条件判断。
“`swift
let isSwiftAwesome: Bool = true
let needsLogin = falseif isSwiftAwesome {
print(“Indeed!”)
} else {
print(“Hmm, maybe give it another try?”)
}
“` -
字符串 (Strings):
String
用于表示一系列字符。Swift 的String
类型是值类型,并且完全支持 Unicode。
“`swift
let greeting: String = “Hello”
let name = “Bob”
let personalizedGreeting = greeting + “, ” + name + “!” // 字符串拼接
print(personalizedGreeting) // 输出 “Hello, Bob!”// 字符串插值 (String Interpolation) – 更推荐的方式
let score = 88
let scoreMessage = “Your score is (score).” // 将变量或表达式嵌入字符串
print(scoreMessage) // 输出 “Your score is 88.”let multiLineString = “””
This is a string
that spans multiple
lines.
“””
print(multiLineString)// 字符串常用操作
print(“The message has (message.count) characters.”) // 获取长度
if message.isEmpty { print(“String is empty.”) } // 检查是否为空
print(message.uppercased()) // 转大写
print(message.lowercased()) // 转小写
if message.hasPrefix(“Sw”) { print(“Starts with Sw”) } // 检查前缀
if message.hasSuffix(“ft”) { print(“Ends with ft”) } // 检查后缀
“` -
字符 (Characters):
Character
表示单个字符。需要显式注解类型。
swift
let firstLetter: Character = "A"
let exclamationMark: Character = "!"
4. 运算符 (Operators)
Swift 支持标准 C 语言中的大部分运算符,并进行了一些改进。
-
赋值运算符 (Assignment Operator):
=
用于给变量赋值。
swift
var x = 10
x = 5 -
算术运算符 (Arithmetic Operators):
+
(加),-
(减),*
(乘),/
(除),%
(取余)。
swift
let sum = 5 + 3 // 8
let difference = 10 - 4 // 6
let product = 2 * 6 // 12
let quotient = 10 / 3 // 3 (整数除法,结果也是整数)
let floatQuotient = 10.0 / 3.0 // 3.333... (浮点数除法)
let remainder = 10 % 3 // 1
注意: Swift 不允许数值溢出(除非使用特殊的溢出运算符&+
,&-
,&*
)。 -
复合赋值运算符 (Compound Assignment Operators):
+=
,-=
,*=
,/=
,%=
等,是算术运算和赋值的结合。
swift
var score = 100
score += 10 // score = score + 10 => 110
score -= 5 // score = score - 5 => 105 -
比较运算符 (Comparison Operators):
==
(等于),!=
(不等于),>
(大于),<
(小于),>=
(大于等于),<=
(小于等于)。返回布尔值 (true
或false
)。
swift
let a = 5
let b = 10
print(a == b) // false
print(a != b) // true
print(a < b) // true -
逻辑运算符 (Logical Operators):
!
(逻辑非),&&
(逻辑与),||
(逻辑或)。用于组合布尔值。
“`swift
let isRaining = true
let hasUmbrella = falseif isRaining && hasUmbrella {
print(“Go out.”)
} else if isRaining && !hasUmbrella {
print(“Stay inside or get wet!”) // 这会被打印
} else {
print(“Enjoy the weather!”)
}
“` -
范围运算符 (Range Operators): 用于表示一个区间。
- 闭区间运算符 (Closed Range Operator):
a...b
表示从a
到b
包含a
和b
的范围。
swift
for index in 1...5 { // 包含 1, 2, 3, 4, 5
print(index)
} - 半开区间运算符 (Half-Open Range Operator):
a..<b
表示从a
到b
但不包含b
的范围。
swift
let names = ["Anna", "Alex", "Brian", "Jack"]
for i in 0..<names.count { // 包含 0, 1, 2, 3 (不包含 4)
print("Person \(i + 1) is \(names[i])")
} - 单侧范围 (One-Sided Ranges):
a...
,...b
,..<b
用于表示从某个点开始或到某个点结束的范围,常用于数组切片等。
swift
let numbers = [10, 20, 30, 40, 50]
let firstThree = numbers[..<3] // [10, 20, 30]
let fromIndexTwo = numbers[2...] // [30, 40, 50]
- 闭区间运算符 (Closed Range Operator):
-
三元条件运算符 (Ternary Conditional Operator):
condition ? valueIfTrue : valueIfFalse
,是if-else
语句的简洁形式。
swift
let currentTemp = 25
let weatherMessage = currentTemp >= 30 ? "It's hot!" : "It's pleasant."
print(weatherMessage) // 输出 "It's pleasant."
5. 集合类型 (Collection Types)
Swift 提供了三种主要的集合类型来存储值的集合:数组 (Arrays)、字典 (Dictionaries) 和集合 (Sets)。
5.1 数组 (Arrays)
数组是有序的值的集合,元素类型必须相同。
-
创建数组:
“`swift
// 创建一个空数组
var emptyIntArray: [Int] = []
var anotherEmptyArray = String// 使用数组字面量创建数组 (常用)
var shoppingList = [“Eggs”, “Milk”, “Bread”] // 推断为 [String]
let fibonacci: [Int] = [1, 1, 2, 3, 5, 8]// 创建包含默认值的数组
var threeDoubles = Array(repeating: 0.0, count: 3) // [0.0, 0.0, 0.0]
“` -
访问和修改数组:
“`swift
print(“Shopping list has (shoppingList.count) items.”) // 获取数量
if shoppingList.isEmpty { print(“The list is empty.”) } // 检查是否为空// 访问元素 (使用下标,从 0 开始)
let firstItem = shoppingList[0] // “Eggs”
print(“First item: (firstItem)”)// 修改元素
shoppingList[1] = “Almond Milk” // [“Eggs”, “Almond Milk”, “Bread”]// 添加元素
shoppingList.append(“Butter”) // [“Eggs”, “Almond Milk”, “Bread”, “Butter”]
shoppingList += [“Cheese”] // [“Eggs”, “Almond Milk”, “Bread”, “Butter”, “Cheese”]
shoppingList.insert(“Apples”, at: 0) // 在指定位置插入// 删除元素
let removedItem = shoppingList.remove(at: 1) // 删除 “Eggs”,返回被删除的元素
let lastItem = shoppingList.removeLast() // 删除最后一个元素 “Cheese”
print(shoppingList) // [“Apples”, “Almond Milk”, “Bread”, “Butter”]
“` -
遍历数组:
“`swift
for item in shoppingList {
print(item)
}// 如果需要索引和值
for (index, value) in shoppingList.enumerated() {
print(“Item (index + 1): (value)”)
}
“`
5.2 字典 (Dictionaries)
字典是无序的键值对 (key-value pairs) 集合。每个键 (key) 必须是唯一的,并且键的类型必须是可哈希的(如 String
, Int
, Double
, Bool
等)。值的类型没有此限制,但同一个字典中的所有值的类型必须相同。
-
创建字典:
“`swift
// 创建一个空字典
var emptyStringDict: [String: String] = [:]
var anotherEmptyDict = Int: Float// 使用字典字面量创建 (常用)
var airports: [String: String] = [“YYZ”: “Toronto Pearson”, “DUB”: “Dublin”]
let studentScores = [“Alice”: 95, “Bob”: 88] // 推断为 [String: Int]
“` -
访问和修改字典:
“`swift
print(“Number of airports: (airports.count)”) // 获取数量
if airports.isEmpty { print(“Dictionary is empty.”) }// 访问值 (使用键) – 返回的是可选类型 (Optional),因为键可能不存在
if let torontoAirport = airports[“YYZ”] {
print(“YYZ airport is: (torontoAirport)”)
} else {
print(“Airport code not found.”)
}// 添加或更新键值对 (使用下标)
airports[“LHR”] = “London Heathrow” // 添加新键值对
airports[“YYZ”] = “Toronto Pearson International” // 更新现有键的值
print(airports)// 使用 updateValue(_:forKey:) 方法,会返回旧值 (可选类型)
if let oldValue = airports.updateValue(“Dublin Airport”, forKey: “DUB”) {
print(“Updated DUB from (oldValue)”)
}// 删除键值对
airports[“LHR”] = nil // 通过赋值 nil 删除
if let removedValue = airports.removeValue(forKey: “DUB”) { // removeValue 返回被删除的值 (可选)
print(“Removed Dublin airport.”)
}
print(airports) // [“YYZ”: “Toronto Pearson International”]
“` -
遍历字典:
“`swift
// 遍历键值对 (元组)
for (airportCode, airportName) in airports {
print(“(airportCode): (airportName)”)
}// 只遍历键
for airportCode in airports.keys {
print(“Airport code: (airportCode)”)
}// 只遍历值
for airportName in airports.values {
print(“Airport name: (airportName)”)
}// 如果需要排序的键或值
let sortedKeys = airports.keys.sorted()
for key in sortedKeys {
print(“(key): (airports[key]!)”) // 注意这里强制解包了,后面会讲 Optional
}
“`
5.3 集合 (Sets)
集合是无序的、唯一值的集合。集合中的元素类型也必须是可哈希的。当你关心的是元素是否存在,而不关心顺序或重复时,使用集合。
-
创建集合:
“`swift
// 创建一个空集合
var emptyLetterSet: Set= []
var anotherEmptySet = Set() // 使用数组字面量创建 (需要显式类型注解)
var favoriteGenres: Set= [“Rock”, “Classical”, “Hip hop”] // 集合会自动去除重复项
let repeatedNumbers: Set= [1, 2, 2, 3, 1, 4]
print(repeatedNumbers) // 输出类似 {2, 4, 1, 3} (顺序不定)
“` -
访问和修改集合:
“`swift
print(“Number of genres: (favoriteGenres.count)”)
if favoriteGenres.isEmpty { print(“Set is empty.”) }// 检查元素是否存在 (高效)
if favoriteGenres.contains(“Rock”) {
print(“Rock is a favorite genre.”)
}// 添加元素 (如果元素已存在,则无效果)
favoriteGenres.insert(“Jazz”)
print(favoriteGenres) // { “Classical”, “Rock”, “Jazz”, “Hip hop” } (顺序不定)// 删除元素 (如果元素存在,返回被删除的元素;否则返回 nil)
if let removedGenre = favoriteGenres.remove(“Classical”) {
print(“(removedGenre) was removed.”)
}
print(favoriteGenres) // { “Rock”, “Jazz”, “Hip hop” } (顺序不定)
“` -
集合操作: 集合非常适合执行标准的集合运算。
“`swift
let oddDigits: Set = [1, 3, 5, 7, 9]
let evenDigits: Set = [0, 2, 4, 6, 8]
let primeDigits: Set = [2, 3, 5, 7]// 并集 (union): 包含两个集合所有元素的集合
let unionSet = oddDigits.union(evenDigits).sorted() // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]// 交集 (intersection): 只包含两个集合共同元素的集合
let intersectionSet = oddDigits.intersection(primeDigits).sorted() // [3, 5, 7]// 差集 (subtracting): 包含第一个集合中不在第二个集合的元素的集合
let subtractingSet = oddDigits.subtracting(primeDigits).sorted() // [1, 9]// 对称差集 (symmetricDifference): 包含两个集合中非共同元素的集合
let symmetricDiffSet = oddDigits.symmetricDifference(primeDigits).sorted() // [1, 2, 9]// 子集与超集判断
let singleDigitPrimes: Set = [2, 3, 5, 7]
print(singleDigitPrimes.isSubset(of: oddDigits)) // false
print(singleDigitPrimes.isSubset(of: primeDigits)) // true
print(oddDigits.isSuperset(of: singleDigitPrimes)) // false
print(primeDigits.isStrictSubset(of: oddDigits)) // false (不是严格子集)
print(oddDigits.isDisjoint(with: evenDigits)) // true (没有共同元素)
“`
6. 控制流 (Control Flow)
控制流语句用于根据条件或循环来改变代码的执行顺序。
6.1 条件语句 (Conditional Statements)
-
if
,else if
,else
: 根据一个或多个布尔条件执行不同的代码块。
“`swift
let temperature = 15if temperature <= 0 {
print(“It’s freezing!”)
} else if temperature < 10 {
print(“It’s cold.”)
} else if temperature < 20 {
print(“It’s cool.”) // 这会被执行
} else if temperature < 30 {
print(“It’s warm.”)
} else {
print(“It’s hot!”)
}
“` -
switch
: 对一个值进行多路分支判断。Swift 的switch
语句非常强大和灵活。- 不需要
break
:匹配到一个case
后会自动退出switch
语句(除非使用fallthrough
关键字)。 - 必须是完备的 (exhaustive):必须覆盖所有可能的值,否则需要一个
default
分支。 - 可以匹配多种类型的值,包括区间、元组等。
“`swift
let someCharacter: Character = “z”switch someCharacter {
case “a”, “e”, “i”, “o”, “u”: // 匹配多个值
print(“(someCharacter) is a vowel”)
case “b”, “c”, “d”, “f”, “g”, “h”, “j”, “k”, “l”, “m”,
“n”, “p”, “q”, “r”, “s”, “t”, “v”, “w”, “x”, “y”, “z”:
print(“(someCharacter) is a consonant”)
default: // 必须有 default 或覆盖所有情况
print(“(someCharacter) is not a letter”)
}let approximateCount = 62
let countedThings = “moons orbiting Saturn”
var naturalCount: String
switch approximateCount {
case 0:
naturalCount = “no”
case 1..<5: // 匹配范围
naturalCount = “a few”
case 5..<12:
naturalCount = “several”
case 12..<100:
naturalCount = “dozens of” // 这个会匹配
case 100..<1000:
naturalCount = “hundreds of”
default:
naturalCount = “many”
}
print(“There are (naturalCount) (countedThings).”) // “There are dozens of moons orbiting Saturn.”// 匹配元组和值绑定
let somePoint = (1, 1)
switch somePoint {
case (0, 0):
print(“(somePoint) is at the origin”)
case (, 0): // 忽略 x 值
print(“(somePoint) is on the x-axis”)
case (0, ): // 忽略 y 值
print(“(somePoint) is on the y-axis”)
case (-2…2, -2…2): // 匹配 x 和 y 在特定范围内的点
print(“(somePoint) is inside the box”)
case (let x, 0): // 值绑定:将匹配到的 x 绑定到常量 x
print(“On the x-axis with an x value of (x)”)
case (0, let y): // 值绑定:将匹配到的 y 绑定到常量 y
print(“On the y-axis with a y value of (y)”)
case let (x, y) where x == y: // 使用 where 子句添加额外条件
print(“((x), (y)) is on the line x == y”)
case let (x, y): // 绑定所有剩余情况
print(“Somewhere else at ((x), (y))”)
}
“` - 不需要
6.2 循环语句 (Looping Statements)
-
for-in
循环: 遍历一个序列(如范围、数组、字典、集合、字符串等)中的每个元素。
“`swift
// 遍历范围
for i in 1…3 {
print(“Number (i)”)
}// 遍历数组
let fruits = [“Apple”, “Banana”, “Cherry”]
for fruit in fruits {
print(“I like (fruit)”)
}// 遍历字典
let numberOfLegs = [“spider”: 8, “ant”: 6, “cat”: 4]
for (animalName, legCount) in numberOfLegs {
print(“(animalName)s have (legCount) legs”)
}// 如果不需要循环体中的值,可以使用下划线
_
let base = 3
let power = 4
var answer = 1
for _ in 1…power {
answer *= base
}
print(“(base) to the power of (power) is (answer)”) // 81
“` -
while
循环: 在循环开始前检查条件,只要条件为true
就一直执行循环体。
swift
var counter = 5
while counter > 0 {
print("Countdown: \(counter)")
counter -= 1 // 必须在循环体内改变条件相关的变量,否则可能造成无限循环
}
print("Liftoff!") -
repeat-while
循环: 先执行一次循环体,然后在每次迭代结束时检查条件,只要条件为true
就继续循环。确保循环体至少执行一次。
swift
var diceRoll: Int
repeat {
diceRoll = Int.random(in: 1...6) // 产生 1 到 6 的随机整数
print("You rolled a \(diceRoll)")
} while diceRoll != 6 // 一直摇,直到摇出 6
print("You finally rolled a 6!")
6.3 控制转移语句 (Control Transfer Statements)
-
continue
: 跳过当前循环迭代中余下的代码,直接开始下一次迭代。
swift
let puzzleInput = "great minds think alike"
var puzzleOutput = ""
let charactersToRemove: [Character] = ["a", "e", "i", "o", "u", " "]
for character in puzzleInput {
if charactersToRemove.contains(character) {
continue // 如果是元音或空格,跳过本次循环,不添加到 output
}
puzzleOutput.append(character)
}
print(puzzleOutput) // "grtmndsthnklk" -
break
: 立即终止整个控制流语句(switch
或循环)。
swift
let numberToFind = 25
let numbers = [7, 15, 25, 30, 42]
var found = false
for number in numbers {
if number == numberToFind {
found = true
print("Found \(numberToFind)!")
break // 找到就退出循环,不再检查后面的数字
}
print("Checked \(number)...")
} -
fallthrough
: 在switch
语句中,执行完一个case
后,强制继续执行下一个case
的代码块(不常用,需谨慎)。 -
return
: 用于从函数或方法中返回值,并立即退出该函数或方法。 -
throw
: 用于抛出一个错误,通常在可能失败的操作中使用(结合do-catch
处理)。
7. 函数 (Functions)
函数是执行特定任务的独立代码块。Swift 的函数非常灵活。
-
定义和调用函数:
“`swift
// 无参数,无返回值 (返回 Void)
func sayHello() {
print(“Hello!”)
}
sayHello() // 调用函数// 带参数
func greet(person: String) {
print(“Hello, (person)!”)
}
greet(person: “Alice”) // 调用时需要写参数标签 “person:”// 带参数和返回值
func addTwoInts(a: Int, b: Int) -> Int {
let sum = a + b
return sum // 使用 return 返回值
}
let result = addTwoInts(a: 5, b: 3) // 8
print(“Sum is (result)”)// 返回 Optional 类型
func findIndex(of string: String, in array: [String]) -> Int? {
for (index, value) in array.enumerated() {
if value == string {
return index // 找到则返回索引 (Int)
}
}
return nil // 没找到则返回 nil
}
“` -
函数参数标签和参数名称:
- 默认情况下,函数参数同时使用参数标签 (Argument Label) 和参数名称 (Parameter Name)。调用函数时使用参数标签,在函数内部实现时使用参数名称。
- 如果你不希望使用参数标签,可以在参数名称前加上下划线
_
。 - 你也可以指定不同的参数标签和参数名称。
“`swift
// 默认行为:person 是标签也是名称
func greetAgain(person: String) { print(“Hi, (person)!”) }
greetAgain(person: “Bob”)// 省略参数标签
func multiply(_ number: Int, by multiplier: Int) -> Int {
return number * multiplier
}
let product = multiply(4, by: 2) // 第一个参数调用时没有标签
print(product) // 8// 指定不同的标签和名称 (调用时用 from,函数内部用 sender)
func sendMessage(from sender: String, to recipient: String) {
print(“Message from (sender) to (recipient)”)
}
sendMessage(from: “Alice”, to: “Bob”)
“` -
默认参数值: 可以为参数提供默认值。调用时如果省略该参数,则使用默认值。
swift
func power(base: Int, exponent: Int = 2) -> Int { // exponent 默认值为 2
var result = 1
for _ in 1...exponent { result *= base }
return result
}
print(power(base: 3)) // 使用默认 exponent=2,输出 9
print(power(base: 2, exponent: 5)) // 提供 exponent 值,输出 32 -
可变参数 (Variadic Parameters): 接受零个或多个指定类型的值。参数在函数内部表现为一个数组。一个函数最多只能有一个可变参数,且通常是最后一个。
swift
func average(_ numbers: Double...) -> Double { // 接受任意数量的 Double
if numbers.isEmpty { return 0.0 }
var sum = 0.0
for number in numbers { // numbers 在函数内部是 [Double] 类型
sum += number
}
return sum / Double(numbers.count)
}
print(average(1.0, 2.0, 3.0, 4.0)) // 2.5
print(average(5.5, 9.1)) // 7.3
print(average()) // 0.0 -
输入输出参数 (In-Out Parameters): 函数默认不能修改传入的参数值(值类型参数是拷贝传入的)。如果希望函数能修改传入的变量,并将修改传回调用者,可以使用
inout
参数。调用时需要在变量名前加&
。
“`swift
func swapTwoInts(_ a: inout Int, _ b: inout Int) {
let temporaryA = a
a = b
b = temporaryA
}var num1 = 10
var num2 = 20
swapTwoInts(&num1, &num2) // 调用时加 &
print(“num1 is now (num1), num2 is now (num2)”) // num1 is now 20, num2 is now 10
“` -
函数类型 (Function Types): 函数本身也是一种类型。你可以将函数赋值给变量或常量,或者作为参数传递给其他函数,或者作为函数的返回值。
“`swift
func add(a: Int, b: Int) -> Int { return a + b }
func subtract(a: Int, b: Int) -> Int { return a – b }var mathFunction: (Int, Int) -> Int // 声明一个函数类型的变量
// 它接受两个 Int,返回一个 IntmathFunction = add // 将 add 函数赋值给变量
print(“Result: (mathFunction(5, 3))”) // Result: 8mathFunction = subtract // 将 subtract 函数赋值给变量
print(“Result: (mathFunction(5, 3))”) // Result: 2// 函数作为参数
func printMathResult(_ operation: (Int, Int) -> Int, _ a: Int, _ b: Int) {
let result = operation(a, b)
print(“Math result: (result)”)
}
printMathResult(add, 10, 5) // Math result: 15
printMathResult(subtract, 10, 5) // Math result: 5// 函数作为返回值
func chooseStepFunction(backward: Bool) -> (Int) -> Int {
func stepForward( input: Int) -> Int { return input + 1 }
func stepBackward( input: Int) -> Int { return input – 1 }
return backward ? stepBackward : stepForward
}var currentValue = 3
let moveNearerToZero = chooseStepFunction(backward: currentValue > 0) // 返回 stepBackward 函数while currentValue != 0 {
print(“(currentValue)… “)
currentValue = moveNearerToZero(currentValue) // 调用返回的函数
}
print(“zero!”) // 输出 “3… 2… 1… zero!”
“`
8. 可选类型 (Optionals)
可选类型是 Swift 语言的核心特性之一,用于处理值可能缺失的情况。一个可选类型 (Optional<Type>
或简写 Type?
) 要么包含一个指定类型的值,要么不包含值(即为 nil
)。这解决了许多其他语言中常见的 null
指针/引用问题,强制你在使用前检查值是否存在。
-
声明可选类型: 在类型名后加问号
?
。
swift
var optionalString: String? = "Hello" // 可能包含 String,也可能为 nil
var anotherOptional: Int? // 默认值为 nil -
nil: 表示值的缺失。只能赋给可选类型变量。
swift
optionalString = nil -
解包 (Unwrapping) 可选类型: 为了访问可选类型中包含的值,你需要先解包它。有几种安全的方式:
-
可选绑定 (Optional Binding): 使用
if let
或guard let
来安全地解包。如果可选类型包含值,则将值赋给一个临时常量或变量,并执行代码块;如果为nil
,则跳过代码块。这是最推荐的方式。
“`swift
var serverResponseCode: Int? = 404
// serverResponseCode = nil // 试试改为 nil 看看效果if let code = serverResponseCode {
// 仅当 serverResponseCode 不为 nil 时执行
// code 是一个 Int 常量,其值为 404
print(“Server returned status code: (code)”)
} else {
// 当 serverResponseCode 为 nil 时执行
print(“No response code received.”)
}// guard let 通常用于提前退出函数
func process(responseCode: Int?) {
guard let code = responseCode else {
print(“Cannot process: No response code.”)
return // 如果是 nil,必须退出当前作用域 (如函数)
}
// 在 guard 语句之后,code (解包后的值) 就可以使用了
print(“Processing response code: (code)”)
}
process(responseCode: 200)
process(responseCode: nil)
你可以用逗号分隔,在同一个 `if let` 或 `guard let` 中绑定多个可选值,并添加 `where` 子句。
swift
var userAge: Int? = 30
var userName: String? = “Alice”
if let name = userName, let age = userAge, age >= 18 {
print(“(name) is an adult aged (age).”)
} else {
print(“User data incomplete or user is not an adult.”)
}
“` -
强制解包 (Forced Unwrapping): 在可选类型变量或常量名后加感叹号
!
。极其不推荐,除非你百分之百确定可选类型此刻一定包含值。如果在值为nil
时强制解包,你的程序会崩溃 (crash)。
“`swift
let definitelyAString: String? = “I exist”
// let definitelyNil: String? = nillet unwrappedString = definitelyAString! // “I exist” (如果 definitelyAString 是 nil,这里会崩溃)
print(unwrappedString)// let crashed = definitelyNil! // 这行会直接导致程序崩溃
“` -
隐式解包可选类型 (Implicitly Unwrapped Optionals): 在类型名后加感叹号
!
声明。这种可选类型在使用时不需要显式解包,它会自动解包。但如果在值为nil
时访问它,同样会导致程序崩溃。主要用于某些特定场景(如类初始化过程中属性不能立即赋值,但能保证后续一定有值,或与 Objective-C API 交互时)。应尽量避免使用。
swift
let assumedString: String! = "An implicitly unwrapped optional string"
let implicitString: String = assumedString // 无需 ! 即可访问,但如果 assumedString 是 nil 会崩溃
print(implicitString) -
nil 合并运算符 (Nil-Coalescing Operator):
a ?? b
。如果可选类型a
包含值,则解包并返回该值;如果a
为nil
,则返回默认值b
。b
的类型必须与a
解包后的类型匹配。
“`swift
let defaultColorName = “red”
var userDefinedColorName: String? // nil
var colorNameToUse = userDefinedColorName ?? defaultColorName
print(colorNameToUse) // “red”userDefinedColorName = “blue”
colorNameToUse = userDefinedColorName ?? defaultColorName
print(colorNameToUse) // “blue”
“` -
可选链 (Optional Chaining):
?.
用于在可选类型上安全地调用属性、方法或下标。如果可选类型为nil
,整个链条调用直接失败并返回nil
,不会崩溃。如果可选类型有值,则继续调用,返回的结果仍然是可选类型(因为链条中任何一步都可能失败)。
“`swift
class Person {
var residence: Residence?
}
class Residence {
var numberOfRooms = 1
var address: Address?
func printNumberOfRooms() {
print(“The number of rooms is (numberOfRooms)”)
}
}
class Address {
var streetName: String?
var buildingNumber: String?
}let john = Person()
// john.residence 是 nil// 尝试访问 numberOfRooms
if let roomCount = john.residence?.numberOfRooms { // ?. 如果 residence 是 nil,这里直接返回 nil
print(“John’s residence has (roomCount) room(s).”)
} else {
print(“Unable to retrieve the number of rooms.”) // 这会被打印
}// 尝试调用方法
john.residence?.printNumberOfRooms() // 因为 residence 是 nil,这个方法不会被调用// 尝试访问更深层的属性
let street = john.residence?.address?.streetName // 链式调用,如果 residence 或 address 是 nil,结果就是 nil
print(street) // nil// 甚至可以尝试在可选链后赋值
john.residence = Residence() // 现在 john.residence 有值了
john.residence?.address = Address()
john.residence?.address?.streetName = “123 Fake St” // 赋值成功if let streetName = john.residence?.address?.streetName {
print(“Street name is: (streetName)”) // “Street name is: 123 Fake St”
}
“`
-
9. 结构体与类 (Structures and Classes)
结构体 (struct
) 和类 (class
) 是创建自定义数据类型的通用、灵活的构造体。它们都可以定义属性 (存储值) 和方法 (提供功能)。
-
共同点:
- 定义属性来存储值。
- 定义方法来提供功能。
- 定义下标 (subscripts) 来通过下标语法访问值。
- 定义构造器 (initializers) 来设置初始状态。
- 可以通过扩展 (extension) 来增加功能。
- 可以遵循协议 (protocol) 来提供某种标准功能。
-
类的特有功能:
- 继承 (Inheritance): 一个类可以继承另一个类的特性。
- 类型转换 (Type casting): 允许在运行时检查和解释类实例的类型。
- 析构器 (Deinitializers): 允许类实例在被释放前执行清理操作 (
deinit
)。 - 引用计数 (Reference Counting): 允许多个引用指向同一个类实例。(类是引用类型 Reference Types)
-
结构体的主要特点:
- 结构体是值类型 (Value Types)。当结构体实例被赋值给常量或变量,或者传递给函数时,实际上传递的是它的副本 (copy),而不是引用。对副本的修改不会影响原始实例。
- 数组、字典、集合、字符串、数字、布尔值等 Swift 标准库中的主要类型都是结构体。
- 通常在不需要继承、数据相对简单、希望传递副本以保证独立性时使用结构体。
-
语法:
“`swift
// 定义结构体
struct Resolution {
var width = 0
var height = 0// 方法 func description() -> String { return "Resolution: \(width) x \(height)" }
}
// 定义类
class VideoMode {
var resolution = Resolution() // 包含一个结构体实例作为属性
var interlaced = false
var frameRate = 0.0
var name: String? // 可选类型属性// 构造器 (Initializer) init(name: String?, frameRate: Double) { self.name = name // 使用 self 区分属性和参数名 self.frameRate = frameRate } // 便利构造器 (Convenience Initializer) - 可选 convenience init(name: String) { self.init(name: name, frameRate: 30.0) // 必须调用同一个类中的指定构造器 } // 析构器 (仅类可用) deinit { // 清理操作,例如释放资源 print("Deinitializing VideoMode instance") } // 方法 func detailedDescription() -> String { var desc = "VideoMode: \(resolution.description()), Frame Rate: \(frameRate), Interlaced: \(interlaced)" if let name = name { // 处理可选属性 desc += ", Name: \(name)" } return desc }
}
“` -
实例创建:
“`swift
// 创建结构体实例
var vga = Resolution(width: 640, height: 480) // 结构体有默认的成员构造器 (如果没自定义)
var cinema = Resolution() // 使用默认值 0x0
cinema.width = 2048// 创建类实例 (必须使用构造器)
let someVideoMode = VideoMode(name: “1080p”, frameRate: 60.0)
let anotherVideoMode = VideoMode(name: “720p”) // 使用便利构造器
“` -
属性访问: 使用点语法 (
.
)
swift
print("VGA width: \(vga.width)") // 640
print("Video mode frame rate: \(someVideoMode.frameRate)") // 60.0
someVideoMode.frameRate = 30.0 // 可以修改 var 属性 -
值类型 vs 引用类型 演示:
“`swift
// 结构体 (值类型)
let hd = Resolution(width: 1920, height: 1080)
var alsoHd = hd // alsoHd 是 hd 的一个副本alsoHd.width = 1280 // 修改 alsoHd 的 width
print(“hd width: (hd.width)”) // 输出 1920 (原始实例不变)
print(“alsoHd width: (alsoHd.width)”) // 输出 1280 (副本被修改)// 类 (引用类型)
let tenEighty = VideoMode(name: “1080i”, frameRate: 25.0)
tenEighty.interlaced = true
let alsoTenEighty = tenEighty // alsoTenEighty 和 tenEighty 指向同一个实例alsoTenEighty.frameRate = 30.0 // 修改 alsoTenEighty 引用的实例的 frameRate
print(“tenEighty frame rate: (tenEighty.frameRate)”) // 输出 30.0 (原始引用指向的实例被修改了)
print(“alsoTenEighty frame rate: (alsoTenEighty.frameRate)”) // 输出 30.0// 恒等运算符 (Identity Operators): === 和 !==,仅用于比较两个类类型的常量或变量是否引用同一个实例
if tenEighty === alsoTenEighty {
print(“tenEighty and alsoTenEighty refer to the same VideoMode instance.”)
}
“`
何时选择结构体或类?
* 优先考虑使用结构体。
* 当需要 Objective-C 的互操作性时,使用类。
* 当需要控制身份 (identity) 时(例如,需要用 ===
检查实例是否相同),使用类。
* 当需要继承类的特性时,使用类。
* 当需要析构器来管理资源释放时,使用类。
* 其他情况,特别是数据封装和行为定义,且不需要上述类特性时,使用结构体。结构体因其值类型特性,在多线程环境下更安全,也更容易推理代码行为。
10. 错误处理 (Error Handling)
Swift 提供了强大的错误处理模型,允许你优雅地处理程序运行时可能出现的可恢复错误。错误处理涉及四个部分:
-
定义错误类型: 通常使用遵循
Error
协议的枚举 (enum) 来表示不同类型的错误。
swift
enum VendingMachineError: Error {
case invalidSelection
case insufficientFunds(coinsNeeded: Int)
case outOfStock
} -
标记可能抛出错误的函数: 在函数声明的参数列表后、返回箭头
->
前,使用throws
关键字标记该函数可能抛出错误。
“`swift
struct Item {
var price: Int
var count: Int
}class VendingMachine {
var inventory = [
“Candy Bar”: Item(price: 12, count: 7),
“Chips”: Item(price: 10, count: 4),
“Pretzels”: Item(price: 7, count: 11)
]
var coinsDeposited = 0// 这个方法可能抛出上面定义的 VendingMachineError func vend(itemNamed name: String) throws { guard let item = inventory[name] else { throw VendingMachineError.invalidSelection // 抛出错误 } guard item.count > 0 else { throw VendingMachineError.outOfStock // 抛出错误 } guard item.price <= coinsDeposited else { throw VendingMachineError.insufficientFunds(coinsNeeded: item.price - coinsDeposited) // 抛出带有关联值的错误 } coinsDeposited -= item.price var newItem = item newItem.count -= 1 inventory[name] = newItem print("Dispensing \(name)") }
}
“` -
调用可能抛出错误的函数: 使用
try
关键字。有三种方式处理try
:-
do-catch
语句: 将try
调用放在do
代码块中,并在后面跟一个或多个catch
代码块来处理可能抛出的错误。这是最常见的处理方式。
“`swift
let favoriteSnacks = [
“Alice”: “Chips”,
“Bob”: “Licorice”, // 这个会触发 invalidSelection
“Eve”: “Pretzels”,
]func buyFavoriteSnack(person: String, vendingMachine: VendingMachine) {
let snackName = favoriteSnacks[person] ?? “Candy Bar”
print(“(person) is buying (snackName)”)do { // 在 do 块中调用 throwing 函数 try vendingMachine.vend(itemNamed: snackName) print("Enjoy your \(snackName)!") } catch VendingMachineError.invalidSelection { print("Invalid Selection.") } catch VendingMachineError.outOfStock { print("Out of Stock.") } catch VendingMachineError.insufficientFunds(let coinsNeeded) { print("Insufficient funds. Please insert an additional \(coinsNeeded) coins.") } catch { // 通用 catch 块,捕获所有其他类型的 Error print("An unexpected error occurred: \(error)") }
}
let machine = VendingMachine()
machine.coinsDeposited = 20buyFavoriteSnack(person: “Alice”, vendingMachine: machine) // 成功
buyFavoriteSnack(person: “Bob”, vendingMachine: machine) // 失败: Invalid Selection
machine.coinsDeposited = 8 // 充值不够
buyFavoriteSnack(person: “Eve”, vendingMachine: machine) // 失败: Insufficient funds…
“` -
try?
: 将try
调用的结果转换为一个可选类型。如果函数成功执行并返回值,try?
返回包含该值的可选类型;如果函数抛出错误,try?
返回nil
。这种方式忽略了错误的具体类型。
swift
// 假设 vend 函数返回购买的 Item
// func vend(itemNamed name: String) throws -> Item { ... }
// let item = try? machine.vend(itemNamed: "Chips") // item 的类型是 Item?
// if let boughtItem = item { ... } else { /* 购买失败 */ } -
try!
: 禁用错误传递。如果你确定函数绝不会抛出错误,可以使用try!
。但如果函数真的抛出了错误,程序会崩溃。极不推荐,除非你有绝对把握。
-
-
错误传递 (Propagating Errors): 如果一个函数本身不能处理它调用的 throwing 函数抛出的错误,它可以将错误传递给它的调用者。只需在自己的函数声明中也加上
throws
关键字即可。
11. 结语与后续学习
恭喜你!你已经完成了 Swift 快速入门教程,掌握了 Swift 语言的核心基础知识,包括:
- 环境搭建与 Playgrounds 使用
- 常量、变量、类型推断与注解
- 基本数据类型 (Int, Double, Bool, String, Character)
- 常用运算符
- 集合类型 (Array, Dictionary, Set)
- 控制流 (if, switch, for-in, while, repeat-while)
- 函数定义、调用、参数特性与函数类型
- 极其重要的可选类型 (Optionals) 及其安全处理方式
- 结构体与类的定义、区别 (值类型 vs 引用类型) 与选择
- 基本的错误处理机制 (throws, do-catch, try?, try!)
这为你进一步学习 Swift 和进行 Apple 平台(iOS, macOS 等)开发奠定了坚实的基础。
接下来你可以探索:
- 枚举 (Enumerations): 更深入地学习 Swift 强大的枚举,包括关联值和原始值。
- 协议 (Protocols): 学习定义蓝图和实现接口的方式,这是 Swift 面向协议编程的核心。
- 扩展 (Extensions): 如何为现有类型添加新功能。
- 泛型 (Generics): 编写灵活、可复用的代码,适用于多种类型。
- 自动引用计数 (ARC): 了解 Swift 如何管理内存。
- 并发 (Concurrency): 使用
async/await
等现代 Swift 特性处理异步操作。 - SwiftUI 或 UIKit/AppKit: 开始学习构建用户界面的框架。
推荐资源:
- 官方文档: The Swift Programming Language (Swift 5.7 or later) – 最权威、最全面的参考。
- Apple Developer Documentation: 包含大量教程、示例代码和 API 参考。
- Hacking with Swift: Paul Hudson 提供了大量免费的 Swift 和 SwiftUI 教程。
- Swift.org: 获取 Swift 开源项目信息和工具链下载。
- 在线社区: Stack Overflow、Swift Forums 等。
最重要的是多实践!尝试修改教程中的示例,自己编写小程序,或者开始一个简单的项目。编程是一门实践性很强的技能,动手越多,掌握越快。祝你在 Swift 的学习旅程中一帆风顺!