Swift 编程入门 – wiki基地


扬帆起航: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?

  1. 现代与安全: Swift 吸收了现代语言的先进思想,许多常见的编程错误(如空指针引用)在编译阶段就能被捕获,大大提高了代码的安全性。它强制要求在使用可能为 nil 的变量前进行安全处理(Optionals),避免了 Objective-C 中常见的奔溃问题。
  2. 快速: Swift 编译器经过优化,能够生成高性能的代码。它在很多任务上比 Objective-C 运行得更快。
  3. 富有表现力与易读: Swift 的语法简洁直观,更接近自然语言,使得代码更易于阅读和编写。它支持类型推断,可以减少代码冗余。
  4. 强大的工具支持: 结合 Xcode 开发环境,Swift 提供了强大的工具链,包括交互式的 Playgrounds(一个让你实时看到代码执行结果的环境)、先进的调试器和性能分析工具。
  5. 开源与社区: Swift 是开源的(swift.org),拥有一个活跃的全球社区。这促进了语言的持续发展和跨平台应用。
  6. 未来趋势: 苹果公司正在将越来越多的系统框架迁移到 Swift,并且新的技术(如 SwiftUI)主要或仅支持 Swift。掌握 Swift 是开发苹果平台应用的长远之计。

第二章: 环境搭建与你的第一个 Swift 程序

学习 Swift,最推荐的环境是苹果官方提供的集成开发环境(IDE)—— Xcode。

环境搭建:Xcode

  1. 下载 Xcode: 如果你使用的是 Mac 电脑,可以直接从 Mac App Store 免费下载 Xcode。Xcode 体积较大,下载和安装可能需要一些时间。
  2. 安装: 下载完成后,按照提示进行安装。
  3. 启动: 安装完毕后,在“应用程序”文件夹中找到并打开 Xcode。

初识 Xcode Playground

对于初学者来说,Xcode Playgrounds 是一个极好的起点。它允许你编写 Swift 代码并立即看到执行结果,无需创建一个完整的项目。

  1. 创建 Playground: 打开 Xcode,选择 File -> New -> Playground...
  2. 选择模板: 选择 Blank 模板,点击 Next
  3. 命名和保存: 给你的 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, playgroundprint() 是一个常用的函数,用于在控制台输出信息。

你的第一个 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): 用于存储逻辑值,只有两个可能的值:truefalse。通常用于条件判断。
    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): 用于比较两个值,结果是布尔值 (truefalse)。
    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 letguard 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, continuethrow)。这有助于避免“厄运金字塔”(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 不会影响 p1

    print(“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: Int

    init(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 也会影响 person1

    print(“person1’s age is (person1.age)”) // 输出: person1’s age is 31
    print(“person2’s age is (person2.age)”) // 输出: person2’s age is 31

    person1.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 的核心语法和基本概念。这只是冰山一角,但你已经具备了进一步深入学习的基础。接下来你可以:

  1. 深入学习更高级的 Swift 特性: 错误处理、泛型、协议导向编程、高级集合操作、内存管理(ARC)、属性包装器、结果类型(Result)等。
  2. 学习苹果平台的 UI 开发:
    • SwiftUI: 苹果最新的声明式 UI 框架,跨平台(iOS, macOS, watchOS, tvOS),使用 Swift 编写。更现代、更易于上手。
    • UIKit (iOS/tvOS) / AppKit (macOS): 苹果传统的命令式 UI 框架,依然广泛使用。
  3. 学习特定领域的开发: Core Data (数据持久化)、Core Animation (动画)、Combine (响应式编程)、Machine Learning (机器学习) 等。
  4. 学习服务器端 Swift: 了解 Vapor、Kitura 等框架,使用 Swift 构建后端服务。
  5. 练习: 最重要的是通过编写代码来巩固所学。从小型项目开始,例如一个计算器应用、一个待办事项列表、一个简单的游戏等。
  6. 阅读官方文档: Swift 语言指南 (The Swift Programming Language) 是最权威、最详细的资源。虽然一开始可能有些枯燥,但它是查找特定语法细节和深入理解概念的最佳途径。
  7. 参与社区: 访问 Swift 论坛、Stack Overflow、GitHub 等,阅读其他人的代码,提问和回答问题。
  8. 在线课程和教程: 有大量优秀的在线平台(如 Stanford 的 CS193p 课程、Udemy、Coursera、B站等)提供 Swift 和苹果开发课程。

总结

Swift 是一门充满活力、现代且功能强大的编程语言。它通过强调安全性、速度和易读性,使得开发苹果平台的应用变得更加愉悦和高效。从常量变量到可选类型,从结构体类到协议扩展,你已经触及了 Swift 的核心。并发模型 async/await 的引入更是让异步编程变得前所未有的清晰。

编程是一项需要不断学习和实践的技能。这篇入门文章为你奠定了基础,但真正的学习始于你写下第一行代码、遇到第一个错误、解决第一个难题。

勇敢地去尝试吧!启动 Xcode,打开 Playgrounds,或者创建一个新的项目。将你学到的知识付诸实践,不断探索 Swift 的无限可能。祝你在 Swift 的世界里扬帆远航,创造出令人惊叹的应用!


发表评论

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

滚动至顶部