简单值(Simple Values)
- 常量与变量
swift
// 常量:一次性赋值
let maximumNumberOfLoginAttempts = 10
// 变量:可反复修改
var currentLoginAttempt = 0
编译器自动推断类型,也可以显式标注:
swift
let π: Double = 3.14159
- 类型转换必须显式
swift
let width = 94
let message = "The width is " + String(width) // ✅ 必须包一层
// Swift 不支持隐式转换:String + Int → 编译错误
- 字符串插值(推荐写法)
swift
let apples = 3
let oranges = 5
let fruitSummary = "I have \(apples + oranges) pieces of fruit."
- 多行字符串
swift
let quotation = """
Even though there's whitespace to the left,
the actual lines aren't indented.
But this line is indented!
"""
// 缩进以结尾 """ 的位置为准,自动裁剪左侧空格。
- 数组 & 字典
swift
var shoppingList = ["eggs", "milk"] // 数组自动 [String]
shoppingList.append("flour") // 可追加
var occupations = ["Malcolm": "Captain",
"Kaylee": "Mechanic"]
occupations["Jayne"] = "Public Relations" // 新增键值
空数组、空字典写法:
swift
let emptyArray: [String] = []
let emptyDict: [String: Float] = [:]
// 如果左侧无类型信息,必须显式声明类型
控制流(Control Flow)
- if / switch / for / while 概览
swift
let score = 99
if score > 90 {
print("Great")
} else {
print("OK")
}
条件必须是 Bool,不能写 if score { ... }
(C 语言坏习惯在这里直接报错)。
- 可选型(Optional)
swift
var optionalString: String? = "Hello"
optionalString = nil // 现在里面没东西
// 经典拆包
if let name = optionalString {
print("The name is \(name)")
} else {
print("No name")
}
// 提供默认值
let nickName = optionalString ?? "anonymous"
- switch 可以匹配任意类型,不用 break
swift
let vegetable = "red pepper"
switch vegetable {
case "celery":
print("Add raisins")
case let x where x.hasSuffix("pepper"):
print("Is it a spicy \(x)?")
default:
print("Everything else")
}
// 匹配成功后自动跳出,不会 fallthrough
- 区间运算符
swift
// 半开区间:0..<4 → 0,1,2,3
// 闭合区间:0...4 → 0,1,2,3,4
for n in 0..<4 {
print(n)
}
函数与闭包(Functions & Closures)
- 函数定义 & 调用
swift
@discardableResult
func greet(person: String, day: String) -> String {
return "Hello \(person), today is \(day)."
}
greet(person: "Tom", day: "Wednesday")
默认参数名就是标签,可自定义:
swift
func greet(_ person: String, on day: String) -> String {
return "Hello \(person), today is \(day)."
}
greet("Tom", on: "Wednesday")
- 返回多值:Tuple
swift
func calculate(scores: [Int]) -> (min: Int, max: Int, sum: Int) {
var min = scores[0], max = scores[0], sum = 0
for s in scores {
if s < min { min = s }
if s > max { max = s }
sum += s
}
return (min, max, sum)
}
let statistics = calculate(scores: [5, 3, 100, 9])
print(statistics.sum) // 117
print(statistics.2) // 下标也行
- 嵌套函数 = 闭包的一种
swift
func returnFifteen() -> Int {
var y = 10
func add() { y += 5 } // 嵌套函数可以捕获外部变量
add()
return y
}
- 一等公民:函数作参数 / 返回值
swift
func makeIncrementer() -> ((Int) -> Int) {
func addOne(number: Int) -> Int {
return 1 + number
}
return addOne
}
var increment = makeIncrementer()
increment(7) // 8
- 闭包简写(实际开发最常用)
swift
let numbers = [2, 19, 7, 42]
var result = numbers.map({ number in 3 * number })
// 更简:numbers.map { 3 * $0 }
print(result) // [6, 57, 21, 126]
如果闭包是最后一个实参,可写在括号外;唯一实参可省略括号:
swift
let sorted = numbers.sorted { $0 > $1 }
对象与类(Objects & Classes)
- 最简单的类
swift
class Shape {
var numberOfSides = 0
func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides."
}
}
var shape = Shape()
shape.numberOfSides = 7
print(shape.simpleDescription())
- 指定构造器(init)与析构器(deinit)
swift
class NamedShape {
var numberOfSides: Int
let name: String
init(name: String, sides: Int) {
self.name = name
self.numberOfSides = sides
}
deinit {
// 对象释放前清理,比如关闭文件
print("\(name) is being deinitialized")
}
func description() -> String {
return "\(name) with \(numberOfSides) sides"
}
}
- 继承 & 重写(override)
swift
class Square: NamedShape {
var sideLength: Double
init(sideLength: Double, name: String) {
self.sideLength = sideLength
super.init(name: name, sides: 4)
}
func area() -> Double {
return sideLength * sideLength
}
override func description() -> String {
return "Square: \(super.description()), area=\(area())"
}
}
- 存储属性 vs 计算属性
swift
class EquilateralTriangle: NamedShape {
var sideLength: Double = 0.0
init(sideLength: Double, name: String) {
self.sideLength = sideLength
super.init(name: name, sides: 3)
}
// 计算属性
var perimeter: Double {
get { return 3 * sideLength }
set {
// newValue 是隐式参数
sideLength = newValue / 3
}
}
}
- 属性观察器(willSet / didSet)
swift
class TriangleAndSquare {
var triangle: EquilateralTriangle {
willSet {
print("Triangle will change, new side=\(newValue.sideLength)")
}
didSet {
// 保证 square 与 triangle 边长同步
square.sideLength = triangle.sideLength
}
}
var square: Square {
didSet {
triangle.sideLength = square.sideLength
}
}
init(size: Double, name: String) {
square = Square(sideLength: size, name: "sq")
triangle = EquilateralTriangle(sideLength: size, name: "tri")
}
}
- 可选链(?)
swift
let optionalSquare: Square? = Square(sideLength: 2.5, name: "opt sq")
let side = optionalSquare?.sideLength // 如果为 nil 则返回 nil
枚举与结构体(Enum & Struct)
- 枚举可以带方法
swift
enum Rank: Int {
case ace = 1
case two, three, four, five, six, seven, eight, nine, ten
case jack, queen, king
func simpleDescription() -> String {
switch self {
case .ace: return "ace"
case .jack: return "jack"
case .queen: return "queen"
case .king: return "king"
default: return String(self.rawValue)
}
}
}
let ace = Rank.ace
print(ace.simpleDescription()) // ace
- 从原始值构造(可失败)
swift
if let converted = Rank(rawValue: 11) {
print(converted.simpleDescription()) // jack
}
- 关联值(真正强大的地方)
swift
enum ServerResponse {
case result(String, String) // 日出、日落
case failure(String) // 错误描述
}
let response = ServerResponse.result("06:00", "20:30")
switch response {
case let .result(sunrise, sunset):
print("Sunrise at \(sunrise), sunset at \(sunset)")
case let .failure(msg):
print("Server error: \(msg)")
}
- 结构体(值类型)
swift
struct Card {
var rank: Rank
var suit: Suit // 假设已有枚举 Suit
func description() -> String {
return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
}
}
结构体复制传值,类引用传值;这是 Swift 与 Java 最大的不同之一。
并发(Concurrency)
需要 Swift ≥5.5,编译目标 macOS 12 / iOS 15 以上
- async / await 基础
swift
func fetchUserID(from server: String) async -> Int {
// 模拟网络等待
try? await Task.sleep(nanoseconds: 1_000_000_000)
return Int.random(in: 1...999)
}
func userName(id: Int) async -> String {
try? await Task.sleep(nanoseconds: 500_000_000)
return "user\(id)"
}
- 顺序调用
swift
let id = await fetchUserID(from: "primary")
let name = await userName(id: id)
print(name)
- 并行调用(async let)
swift
async let id = fetchUserID(from: "primary")
async let name = userName(id: 234)
let ret = await name + "====id:\(id)"
print(ret))
- 从同步上下文调用(Task)
swift
Task {
let id = await fetchUserID(from: "backup")
print("Got id \(id)")
}
- Actor:线程安全的"类"
swift
actor TemperatureLogger {
private var records: [Double] = []
let label: String
init(label: String) {
self.label = label
}
func update(with reading: Double) {
records.append(reading)
}
func average() -> Double {
return records.reduce(0, +) / Double(records.count)
}
}
let logger = TemperatureLogger(label: "Living room")
await logger.update(with: 22.5)
print(await logger.average())
访问 actor 内部状态必须 await
,编译器自动保证互斥。
协议与扩展(Protocols & Extensions)
- 协议定义
swift
protocol ExampleProtocol {
var simpleDescription: String { get }
mutating func adjust() // 结构体实现时需加 mutating
}
- 类 / 结构体 / 枚举都能遵守
swift
class SimpleClass: ExampleProtocol {
var simpleDescription: String = "A very simple class"
var anotherProperty: Int = 69105
func adjust() {
simpleDescription += " (adjusted)"
}
}
struct SimpleStructure: ExampleProtocol {
var simpleDescription: String = "A simple structure"
// 结构体是值类型,修改自身方法需 mutating
mutating func adjust() {
simpleDescription += " (adjusted)"
}
}
- 扩展为已有类型加功能
swift
extension Int: ExampleProtocol {
var simpleDescription: String {
return "The number \(self)"
}
mutating func adjust() {
self += 42
}
}
- 把协议当类型用
swift
let protocolValue: ExampleProtocol = SimpleClass()
print(protocolValue.simpleDescription)
// 编译器只能看到协议里定义的成员,anotherProperty 不可见
异常处理(Error Handling)
- 定义错误
swift
enum PrinterError: Error {
case outOfPaper
case noToner
case onFire
}
- 抛错 & 标记
swift
func send(job: Int, toPrinter printerName: String) throws -> String {
if printerName == "Never Has Toner" {
throw PrinterError.noToner
}
return "Job sent"
}
- do-catch 处理
swift
do {
let result = try send(job: 1040, toPrinter: "Never Has Toner")
print(result)
} catch PrinterError.noToner {
print("请更换墨粉")
} catch { // 兜底
print("其他打印错误:\(error)")
}
- try? 转可选
swift
let result = try? send(job: 1440, toPrinter: "Gutenberg")
// 成功则包 .some,失败为 nil,适合不关心具体错误场景
- defer:扫尾工作
swift
func processFile(filename: String) throws {
let file = open(filename, 2)
defer {
close(file) // 函数退出前**一定**执行
}
try operate(on: file)
}
泛型(Generics)
- 泛型函数
swift
func makeArray<Item>(repeating item: Item, numberOfTimes: Int) -> [Item] {
var result: [Item] = []
for _ in 0..<numberOfTimes {
result.append(item)
}
return result
}
makeArray(repeating: "knock", numberOfTimes: 4)
- 泛型类型
swift
struct Stack<Element> {
private var items: [Element] = []
mutating func push(_ item: Element) { items.append(item) }
mutating func pop() -> Element { items.removeLast() }
}
- where 约束
swift
func anyCommonElements<T: Sequence, U: Sequence>(_ lhs: T, _ rhs: U) -> Bool
where T.Element: Equatable, T.Element == U.Element
{
for lhsItem in lhs {
for rhsItem in rhs {
if lhsItem == rhsItem { return true }
}
}
return false
}
anyCommonElements([1, 2, 3], [3]) // true
总结与实战建议
-
Swift 的安全体现在:
- 变量必须初始化;
- 类型转换显式;
- 可选型强制处理;
- 数组越界直接运行时错误。
写 Swift 会"被迫"把空值、边界、异常都考虑到,这恰恰减少了线上崩溃。
-
值类型优先思维:
官方鼓励先用
struct
,需要继承、共享状态、deinit 时才用class
。在 UIKit / SwiftUI 里,Model 层大量采用
struct
+let
保证数据流单向不可变。 -
协议导向编程:
不同于 Java 的接口,Swift 协议可以带默认实现、关联类型、泛型
where
约束。利用 extension 给系统类型(如
Int
、String
)追加协议,可写出极度简洁的 DSL。 -
并发模型:
async/await
+actor
让回调地狱消失,同时比 GCD 更容易推理执行顺序。注意:
- 老项目混用 GCD 时,可用
Task { ... }
桥接; - 大量 CPU 密集任务,仍然使用 GCD 全局队列或
Task.detached
。
- 老项目混用 GCD 时,可用
-
实战踩坑小贴士:
- 闭包循环引用:捕获
self
时别忘[weak self]
; - 枚举关联值无法自动
Equatable
,需要手写或enum MyEnum: Equatable
; - 泛型约束复杂时,优先用
where
子句而不是层层嵌套<T: A & B & C>
,可读性更好。
- 闭包循环引用:捕获