Swift 快速入门教程 – wiki基地


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 插件进行开发。
  • 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 + 1

    var 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 不允许 IntDouble/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 只有两个可能的值:truefalse。常用于条件判断。
    “`swift
    let isSwiftAwesome: Bool = true
    let needsLogin = false

    if 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): == (等于), != (不等于), > (大于), < (小于), >= (大于等于), <= (小于等于)。返回布尔值 (truefalse)。
    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 = false

    if 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 表示从 ab 包含 ab 的范围。
      swift
      for index in 1...5 { // 包含 1, 2, 3, 4, 5
      print(index)
      }
    • 半开区间运算符 (Half-Open Range Operator): a..<b 表示从 ab 但不包含 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]
  • 三元条件运算符 (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 = 15

    if 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,返回一个 Int

    mathFunction = add // 将 add 函数赋值给变量
    print(“Result: (mathFunction(5, 3))”) // Result: 8

    mathFunction = 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 letguard 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? = nil

      let 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 包含值,则解包并返回该值;如果 anil,则返回默认值 bb 的类型必须与 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 提供了强大的错误处理模型,允许你优雅地处理程序运行时可能出现的可恢复错误。错误处理涉及四个部分:

  1. 定义错误类型: 通常使用遵循 Error 协议的枚举 (enum) 来表示不同类型的错误。
    swift
    enum VendingMachineError: Error {
    case invalidSelection
    case insufficientFunds(coinsNeeded: Int)
    case outOfStock
    }

  2. 标记可能抛出错误的函数: 在函数声明的参数列表后、返回箭头 -> 前,使用 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)")
    }
    

    }
    “`

  3. 调用可能抛出错误的函数: 使用 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 = 20

      buyFavoriteSnack(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!。但如果函数真的抛出了错误,程序会崩溃极不推荐,除非你有绝对把握。

  4. 错误传递 (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 的学习旅程中一帆风顺!


发表评论

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

滚动至顶部