优秀的编程知识分享平台

网站首页 > 技术文章 正文

Swift 语言学习指南 - 中篇:高级特性

nanyue 2025-03-03 19:34:11 技术文章 6 ℃

1. 面向对象编程

1.1 类与结构体

1.1.1 定义与区别

在 Swift 中,类和结构体都是用于封装数据和行为的类型。不过它们存在一些关键区别:

  • :是引用类型,多个变量可以引用同一个类的实例,一个实例的改变会反映在所有引用它的变量上。类支持继承,允许创建类的层次结构。
  • 结构体:是值类型,当一个结构体实例被赋值给另一个变量或作为参数传递时,会进行值的复制,新的实例和原实例是独立的。结构体不支持继承。

1.1.2 类的定义与使用

// 定义一个类
class Person {
    var name: String
    var age: Int

    // 构造函数
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }

    // 实例方法
    func introduce() {
        print("My name is \(name) and I'm \(age) years old.")
    }
}

// 创建类的实例
let person = Person(name: "Alice", age: 25)
person.introduce()

1.1.3 结构体的定义与使用

// 定义一个结构体
struct Point {
    var x: Double
    var y: Double

    // 实例方法
    func distanceToOrigin() -> Double {
        return sqrt(x * x + y * y)
    }
}

// 创建结构体的实例
let point = Point(x: 3.0, y: 4.0)
let distance = point.distanceToOrigin()
print("Distance to origin: \(distance)")

1.2 属性与方法

1.2.1 属性

  • 存储属性:用于存储实例的数据,在类和结构体中都可以使用。
class Student {
    // 存储属性
    var name: String
    var grade: Int

    init(name: String, grade: Int) {
        self.name = name
        self.grade = grade
    }
}
  • 计算属性:不直接存储值,而是通过计算得到值。
struct Rectangle {
    var width: Double
    var height: Double

    // 计算属性
    var area: Double {
        return width * height
    }
}

let rectangle = Rectangle(width: 5.0, height: 10.0)
print("Rectangle area: \(rectangle.area)")

1.2.2 方法

  • 实例方法:属于类或结构体的实例,用于执行与实例相关的操作。
class Counter {
    var count = 0

    // 实例方法
    func increment() {
        count += 1
    }
}

let counter = Counter()
counter.increment()
print("Counter value: \(counter.count)")
  • 类方法:使用 static(对于结构体和枚举)或 class(对于类)关键字声明,属于类型本身,而不是实例。
class MathUtils {
    // 类方法
    class func add(_ a: Int, _ b: Int) -> Int {
        return a + b
    }
}

let sum = MathUtils.add(3, 5)
print("Sum: \(sum)")

1.3 继承、多态与访问控制

1.3.1 继承

类可以继承其他类的属性和方法,被继承的类称为父类,继承的类称为子类。

// 父类
class Vehicle {
    var speed: Double = 0.0

    func move() {
        print("The vehicle is moving at \(speed) km/h.")
    }
}

// 子类
class Car: Vehicle {
    var brand: String

    init(brand: String) {
        self.brand = brand
        super.init()
    }

    override func move() {
        print("The \(brand) car is moving at \(speed) km/h.")
    }
}

let car = Car(brand: "Toyota")
car.speed = 60.0
car.move()

1.3.2 多态

多态允许不同类的对象通过相同的接口进行交互。通过继承和方法重写可以实现多态。

let vehicles: [Vehicle] = [Vehicle(), Car(brand: "Honda")]
for vehicle in vehicles {
    vehicle.move()
}

1.3.3 访问控制

Swift 提供了几种访问控制级别,包括 private、fileprivate、internal、public 和 open,用于限制代码的访问权限。

// private 访问控制
class PrivateExample {
    private var privateProperty = 10

    private func privateMethod() {
        print("This is a private method.")
    }
}

// internal 访问控制(默认级别)
class InternalExample {
    var internalProperty = 20

    func internalMethod() {
        print("This is an internal method.")
    }
}

2. 枚举与可选类型

2.1 枚举的定义与使用

枚举用于定义一组相关的值。

// 定义一个简单的枚举
enum Weekday {
    case monday
    case tuesday
    case wednesday
    case thursday
    case friday
    case saturday
    case sunday
}

let today: Weekday = .monday
switch today {
case .monday:
    print("It's Monday!")
default:
    print("It's another day.")
}

2.1.1 关联值

枚举可以关联额外的数据。

enum Shape {
    case circle(radius: Double)
    case rectangle(width: Double, height: Double)
}

let circle = Shape.circle(radius: 5.0)
switch circle {
case let .circle(radius):
    print("Circle radius: \(radius)")
default:
    break
}

2.1.2 原始值

枚举可以有原始值,原始值可以是整数、字符串等类型。

enum Planet: Int {
    case mercury = 1
    case venus
    case earth
    case mars
}

let earthIndex = Planet.earth.rawValue
print("Earth's index: \(earthIndex)")

2.2 可选类型

2.2.1 概念与使用

可选类型用于表示一个值可能存在也可能不存在的情况,使用 ? 来声明。

var optionalString: String? = "Hello"
if let unwrappedString = optionalString {
    print("The string is: \(unwrappedString)")
} else {
    print("The string is nil.")
}

2.2.2 可选绑定

可选绑定用于安全地解包可选类型的值。

let numberString: String? = "123"
if let number = Int(numberString ?? "") {
    print("The number is: \(number)")
} else {
    print("Could not convert to a number.")
}

2.2.3 强制解包

使用 ! 可以强制解包可选类型,但如果可选类型为 nil,会导致运行时错误。

let forcedUnwrappedString = optionalString!
print("Forced unwrapped string: \(forcedUnwrappedString)")

2.2.4 空合并运算符

空合并运算符 ?? 用于在可选类型为 nil 时提供一个默认值。

let defaultString = optionalString ?? "Default value"
print("Default string: \(defaultString)")

2.2.5 可选链

可选链用于在可选类型的属性、方法或下标上进行调用,如果可选类型为 nil,调用会失败并返回 nil。

class Person {
    var address: Address?
}

class Address {
    var street: String?
}

let person = Person()
if let street = person.address?.street {
    print("Street: \(street)")
} else {
    print("Street information not available.")
}

3. 协议与扩展

3.1 协议的定义与遵循

协议定义了一组方法、属性和其他要求,类、结构体或枚举可以遵循这些协议。

// 定义一个协议
protocol Drawable {
    func draw()
}

// 结构体遵循协议
struct Square: Drawable {
    func draw() {
        print("Drawing a square.")
    }
}

let square = Square()
square.draw()

3.2 扩展的使用

扩展用于为现有类型添加新的功能,包括方法、计算属性等。

// 为 Int 类型添加一个扩展
extension Int {
    func squared() -> Int {
        return self * self
    }
}

let num = 5
let squaredNum = num.squared()
print("\(num) squared is \(squaredNum)")

3.3 协议扩展

协议扩展可以为协议提供默认的实现,遵循该协议的类型可以使用这些默认实现。

protocol Printable {
    func printInfo()
}

extension Printable {
    func printInfo() {
        print("Default print information.")
    }
}

struct Item: Printable {}

let item = Item()
item.printInfo()

4. 泛型编程

4.1 泛型的概念与语法

泛型用于编写灵活、可复用的代码,允许在定义函数、类、结构体或枚举时使用类型参数。

// 泛型函数
func swapTwoValues(_ a: inout T, _ b: inout T) {
    let temporaryA = a
    a = b
    b = temporaryA
}

var num1 = 10
var num2 = 20
swapTwoValues(&num1, &num2)
print("num1: \(num1), num2: \(num2)")

4.2 泛型类型

可以定义泛型类、结构体和枚举。

// 泛型结构体
struct Stack {
    private var items: [Element] = []

    mutating func push(_ item: Element) {
        items.append(item)
    }

    mutating func pop() -> Element? {
        return items.popLast()
    }
}

var intStack = Stack()
intStack.push(1)
intStack.push(2)
let popped = intStack.pop()
print("Popped: \(popped ?? -1)")

4.3 泛型约束

可以使用泛型约束来限制类型参数必须遵循特定的协议或是特定类型。

// 泛型函数,要求类型参数遵循 Equatable 协议
func findIndex(of valueToFind: T, in array: [T]) -> Int? {
    for (index, value) in array.enumerated() {
        if value == valueToFind {
            return index
        }
    }
    return nil
}

let numbers = [1, 2, 3, 4, 5]
let index = findIndex(of: 3, in: numbers)
print("Index of 3: \(index ?? -1)")

4.4 关联类型与泛型 where 子句

关联类型用于在协议中定义一个占位类型,泛型 where 子句用于对关联类型进行约束。

// 定义一个带有关联类型的协议
protocol Container {
    associatedtype Item
    mutating func append(_ item: Item)
    var count: Int { get }
    subscript(i: Int) -> Item { get }
}

// 泛型结构体遵循协议
struct IntStack: Container {
    typealias Item = Int
    private var items: [Int] = []

    mutating func append(_ item: Int) {
        items.append(item)
    }

    var count: Int {
        return items.count
    }

    subscript(i: Int) -> Int {
        return items[i]
    }
}

// 泛型函数,使用泛型 where 子句
func allItemsMatch(_ container1: C1, _ container2: C2) -> Bool
    where C1.Item == C2.Item, C1.Item: Equatable {
    if container1.count != container2.count {
        return false
    }
    for i in 0..

5. 闭包与高阶函数

5.1 闭包的定义与使用

闭包是自包含的代码块,可以在代码中传递和使用。闭包可以捕获和存储其所在上下文中的常量和变量。

// 定义一个闭包
let greet = { (name: String) in
    print("Hello, \(name)!")
}

// 调用闭包
greet("Bob")

5.2 闭包的捕获值

闭包可以捕获其所在上下文中的常量和变量。

func makeIncrementer(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0
    let incrementer: () -> Int = {
        runningTotal += amount
        return runningTotal
    }
    return incrementer
}

let incrementByTen = makeIncrementer(forIncrement: 10)
print(incrementByTen())
print(incrementByTen())

5.3 高阶函数

高阶函数是指接受一个或多个函数作为参数,或者返回一个函数的函数。

5.3.1 map 函数

map 函数用于对数组中的每个元素应用一个闭包,并返回一个包含结果的新数组。

let numbers = [1, 2, 3, 4, 5]
let squaredNumbers = numbers.map { $0 * $0 }
print("Squared numbers: \(squaredNumbers)")

5.3.2 filter 函数

filter 函数用于根据闭包的条件过滤数组中的元素,并返回一个包含满足条件元素的新数组。

let evenNumbers = numbers.filter { $0 % 2 == 0 }
print("Even numbers: \(evenNumbers)")

5.3.3 reduce 函数

reduce 函数用于将数组中的元素合并成一个单一的值。

let sumOfNumbers = numbers.reduce(0) { $0 + $1 }
print("Sum of numbers: \(sumOfNumbers)")

5.4 逃逸闭包与自动闭包

  • 逃逸闭包:当闭包作为参数传递给函数,但在函数返回后才被调用时,该闭包被称为逃逸闭包,需要使用 @escaping 关键字标记。
var completionHandlers: [() -> Void] = []

func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
    completionHandlers.append(completionHandler)
}

func someFunctionWithNonEscapingClosure(closure: () -> Void) {
    closure()
}

someFunctionWithEscapingClosure {
    print("Escaping closure executed.")
}

someFunctionWithNonEscapingClosure {
    print("Non - escaping closure executed.")
}

completionHandlers.first?()
  • 自动闭包:自动闭包是一种自动创建的闭包,用于包装传递给函数的表达式。使用 @autoclosure 关键字标记。
func logIfTrue(_ predicate: @autoclosure () -> Bool) {
    if predicate() {
        print("The condition is true.")
    }
}

logIfTrue(2 + 2 == 4)

通过学习中篇内容,你已经掌握了 Swift 语言的高级特性,包括面向对象编程、枚举与可选类型、协议与扩展、泛型编程以及闭包与高阶函数。这些知识将帮助你编写更加复杂和灵活的 Swift 代码。在下篇中,我们将聚焦于 Swift 的实战应用和性能优化。

最近发表
标签列表