Swift 中的方法(Methods)是与类型(结构体、类、枚举)关联的函数,用于实现行为。Swift 方法功能强大,支持 mutating、inout、throws、async、实例方法、类型方法、方法重写等。
一、方法分类概览
| 类型 | 说明 | 关键词 |
|---|---|---|
| 实例方法 | 属于实例 | func |
| 类型方法 | 属于类型本身 | static / class |
| 可变方法 | 修改值类型(struct/enum) | mutating |
| 下标方法 | object[i] 语法 | subscript |
| 抛出方法 | 可抛出错误 | throws |
| 异步方法 | 异步执行 | async |
1. 实例方法(Instance Methods)
class Counter {
var count = 0
func increment() {
count += 1
}
func increment(by amount: Int) {
count += amount
}
func reset(to value: Int = 0) {
count = value
}
}
let counter = Counter()
counter.increment()
counter.increment(by: 5)
print(counter.count) // 6
参数标签(Argument Labels)
func move(from start: Int, to end: Int) { ... }
move(from: 0, to: 10) // 清晰语义
省略标签:用
_
func add(_ a: Int, _ b: Int) -> Int { a + b }
add(3, 4) // 简洁
2. 修改值类型:mutating 方法
结构体和枚举是值类型,默认方法不能修改属性。
struct Point {
var x = 0.0, y = 0.0
mutating func moveBy(x deltaX: Double, y deltaY: Double) {
self.x += deltaX
self.y += deltaY
}
// 特殊:可替换 self
mutating func scale(by factor: Double) {
self = Point(x: x * factor, y: y * factor)
}
}
var p = Point(x: 1, y: 2)
p.moveBy(x: 3, y: 4)
print(p) // (4.0, 6.0)
class不需要mutating
3. 类型方法(Type Methods)
struct Math {
static func factorial(_ n: Int) -> Int {
return n <= 1 ? 1 : n * factorial(n - 1)
}
}
class AudioManager {
static let shared = AudioManager()
class func defaultVolume() -> Int { // 可被子类重写
return 50
}
private init() {}
}
print(Math.factorial(5)) // 120
static:不可重写class:仅类可用,可重写
4. 方法重写(Override)
class Vehicle {
func start() {
print("车辆启动")
}
}
class Car: Vehicle {
override func start() {
super.start()
print("汽车引擎轰鸣")
}
}
let car = Car()
car.start()
// 车辆启动
// 汽车引擎轰鸣
5. self 和 Self
struct Box<T> {
var value: T
// 返回同类型实例
func duplicated() -> Self {
return Box(value: value)
}
// 返回同类型(动态)
func asAny() -> Any {
return self
}
}
Self(大写):指当前类型(支持多态)
6. inout 参数:引用传递
允许方法直接修改外部变量。
func swap(_ a: inout Int, _ b: inout Int) {
(a, b) = (b, a)
}
var x = 1, y = 2
swap(&x, &y)
print(x, y) // 2 1
只能传
var,不能是let或字面量
7. 抛出方法(Throwing Functions)
enum ValidationError: Error {
case empty, tooShort, invalidCharacter
}
func validate(username: String) throws {
guard !username.isEmpty else { throw ValidationError.empty }
guard username.count >= 3 else { throw ValidationError.tooShort }
guard username.allSatisfy({ $0.isLetter }) else { throw ValidationError.invalidCharacter }
}
do {
try validate(username: "ab")
} catch {
print(error) // tooShort
}
8. 异步方法(async / await)
import Foundation
actor ImageDownloader {
func downloadImage(from url: URL) async throws -> Data {
let (data, _) = try await URLSession.shared.data(from: url)
return data
}
}
// 使用
Task {
do {
let data = try await ImageDownloader().downloadImage(from: URL(string: "https://example.com/image.jpg")!)
print("下载完成: \(data.count) bytes")
} catch {
print("错误: \(error)")
}
}
9. 下标方法(Subscripts)
自定义 [] 访问语法。
struct Matrix {
let rows: Int, columns: Int
var grid: [Double]
init(rows: Int, columns: Int) {
self.rows = rows
self.columns = columns
grid = Array(repeating: 0.0, count: rows * columns)
}
subscript(row: Int, col: Int) -> Double {
get {
return grid[(row * columns) + col]
}
set {
grid[(row * columns) + col] = newValue
}
}
}
var matrix = Matrix(rows: 2, columns: 2)
matrix[0, 0] = 1.0
matrix[0, 1] = 2.0
print(matrix[0, 0]) // 1.0
多参数 / 类型下标
subscript<T>(key: String) -> T? {
get { ... }
set { ... }
}
10. 方法作为函数(First-Class Functions)
class Calculator {
func add(_ a: Int, _ b: Int) -> Int { a + b }
}
let calc = Calculator()
let operation = calc.add(_:_:) // 方法引用
print(operation(3, 4)) // 7
最佳实践总结
| 场景 | 推荐写法 |
|---|---|
| 值类型修改属性 | mutating func |
| 单例 | static let shared |
| 可重写类型方法 | class func |
| 清晰语义 | 使用参数标签 |
| 简洁调用 | _ 省略标签 |
| 错误处理 | throws + do-catch |
| 异步操作 | async await |
| 数组式访问 | subscript |
常见面试题
mutating是什么?什么时候需要?
→ 值类型(struct/enum)中修改self必须加mutating。selfvsSelf?
→self: 当前实例
→Self: 当前类型(支持返回子类)- 如何防止方法被重写?
→final func或final class inout和普通参数有何不同?
→inout是引用传递,可修改原变量。- 下标可以重载吗?
→ 可以,基于参数数量/类型重载。
小技巧
// 1. 默认参数 + 可变参数
func log(_ items: Any..., separator: String = " ") {
print(items.map { "\($0)" }.joined(separator: separator))
}
log(1, 2, 3) // 1 2 3
// 2. 函数式链式调用
struct Builder {
private var value = ""
mutating func add(_ s: String) -> Self {
value += s
return self
}
func build() -> String { value }
}
let result = Builder().add("A").add("B").build() // "AB"
// 3. @discardableResult 忽略返回值
@discardableResult
func printAndReturn(_ x: Int) -> Int {
print(x)
return x
}
printAndReturn(42) // 不警告未使用返回值
高级话题(可继续提问)
- 方法派发(Method Dispatch)
→ 静态派发 / 动态派发 / 见证表派发(Witness Table) - 协议中的
mutating - Actor 方法隔离
- @objc 和动态派发
- 函数柯里化(Currying)
- SwiftUI 中的
@ViewBuilder方法
需要完整项目示例、性能对比(struct vs class 方法)、或自定义下标实战?欢迎继续提问!