Swift 的特性有哪些?

281 阅读9分钟

面试的时候有问到,毕竟知道特性才能更好的驾驭这门语言,所以总结一下。暂时总结这么多,还有其他的后续再总结吧!

1.安全性和稳定性

  • 例子:在 Swift 中,使用可选类型(Optionals)可以很好地处理可能为空的值。这样可以避免在运行时发生空指针异常。
// Swift 中的可选类型
var optionalName: String? = "John"
// 使用 if let 来处理可选值
if let name = optionalName {
    print("Hello, \(name)")
} else {
    print("Name is nil.")
}

2.简洁易读

  • 例子:Swift 的闭包(Closures)语法相比 Objective-C 的块(Blocks)更加简洁和易读。
  • Swift 中的闭包
// Swift 中的闭包

let numbers = [1, 2, 3, 4, 5]

let squaredNumbers = numbers.map { $0 * $0 }

print(squaredNumbers) // Output: [1, 4, 9, 16, 25]

  • Objective-C 中的闭包(Blocks)
 // Objective-C 中的闭包(Blocks)
   NSArray *numbers = @[@1, @2, @3, @4, @5];
   // 使用 Blocks 实现与 Swift 中的 map 类似的功能
   NSArray *squaredNumbers = [numbers valueForKeyPath:@"@unionOfObjects.self"];
   NSMutableArray *resultArray = [NSMutableArray arrayWithCapacity:squaredNumbers.count];
void (^squareBlock)(NSNumber *, NSUInteger, BOOL *) = ^(NSNumber *number, NSUInteger idx, BOOL *stop) {
NSInteger squaredValue = [number integerValue] * [number integerValue];
[resultArray addObject:@(squaredValue)];};
[numbers enumerateObjectsUsingBlock:squareBlock];
NSLog(@"%@", resultArray); // Output: [1, 4, 9, 16, 25]

3. 动态性能

例子:Swift 允许使用运行时反射来动态查找和操作类型信息,这提供了更多的灵活性

class Dog {
    func bark() {
        print("Woof!")
    }
}

let className = "Dog"
if let classType = NSClassFromString(className) as? NSObject.Type {
    let dog = classType.init() as? Dog
    dog?.bark() // Output: "Woof!"
}

4. 互操作性 例子:Swift 可以轻松地与 Objective-C 代码进行交互,使得在现有的 Objective-C 项目中引入 Swift 变得容易。

// Swift 中与 Objective-C 交互

// Objective-C 声明

// Person.h 【举例说明,没有黏贴.m的实现】

@interface Person : NSObject

- (instancetype)initWithName:(NSString *)name;

- (NSString *)getName;

@end

  
// Swift 使用

let person = Person(name: "Bob")

print(person.getName()) // Output: "Bob"

5.类型推断

例子:Swift 的语法简洁,类型推断和错误检测加强,可以节省开发时间。

// Swift 中的类型推断
let age = 25 // Swift 可以自动推断 age 的类型为 Int
let greeting = "Hello, World!" // Swift 可以自动推断 greeting 的类型为 String

6.元组(Tuples)特性

例子:Swift 引入了元组(Tuples)特性,可以方便地返回多个值。

// Swift 中的元组

func getCoordinates() -> (Double, Double) {
    let latitude = 40.7128
    let longitude = -74.0060
    return (latitude, longitude)
}

let (lat, lon) = getCoordinates()
print("Latitude: \(lat), Longitude: \(lon)") // Output: "Latitude: 40.7128, Longitude: -74.0060"

7.多重返回值(Multiple Return Values)

函数可以返回多个值,而不仅限于一个。

func getUserInfo() -> (name: String, age: Int) {
    return ("John", 30)
}
let userInfo = getUserInfo()
print("Name: \(userInfo.name), Age: \(userInfo.age)") // Output: "Name: John, Age: 30"

8.泛型(Generics)

可以编写更通用、灵活的代码,适用于不同类型的数据。

// 泛型函数

func swapValues<T>(_ a: inout T, _ b: inout T) {
    let temp = a
    a = b
    b = temp
}

var x = 10
var y = 20
swapValues(&x, &y)
print("x: \(x), y: \(y)") // Output: "x: 20, y: 10"

var str1 = "Hello"
var str2 = "World"

swapValues(&str1, &str2)
print("str1: \(str1), str2: \(str2)") // Output: "str1: World, str2: Hello"

9.扩展(Extensions)

可以在已有的类、结构体、枚举等类型中添加新的功能,无需修改原始代码。

// 扩展 String 类型
extension String {
    func reversed() -> String {
        return String(self.reversed())
    }
}

let message = "Swift is awesome!"
let reversedMessage = message.reversed()
print(reversedMessage) // Output: "!emosewa si tfiwS"

10.协议扩展(Protocol Extensions)

可以为协议提供默认的实现,简化遵循协议的类的代码。

// 定义一个简单的协议
protocol Greeting {
    func sayHello()
}

// 通过协议扩展为 sayHello 提供默认实现
extension Greeting {
    func sayHello() {
        print("Hello!")
    }
}
// 实现 Greeting 协议的类可以选择重写 sayHello 方法
class Person: Greeting {
    func sayHello() {
        print("Hi!")
    }
}
let person = Person()
person.sayHello() // Output: "Hi!"

11.错误处理(Error Handling)

使用 Swift 的错误处理机制可以更好地管理和处理可能发生的错误情况。

enum CustomError: Error {
    case networkError
    case fileNotFound
}

 
func processFile() throws {
    // 模拟一个错误情况
    throw CustomError.fileNotFound
}

do {
    try processFile()
} catch CustomError.networkError {
    print("Network error occurred.")
} catch CustomError.fileNotFound {
    print("File not found.")
} catch {
    print("Unknown error.")
}

12.可选链(Optional Chaining)

使用可选链可以在调用属性、方法或下标时检查是否存在值,避免了手动进行nil检查的繁琐过程。

class Person {
    var address: Address?
}


class Address {
    var street: String = "Main Street"
}


let person = Person()
// 使用可选链调用属性
if let street = person.address?.street {
    print(street)
} else {
    print("Address or street not available.")
}

13.函数式编程特性

Swift 支持函数式编程范式,包括高阶函数、map、filter、reduce 等,使得处理集合和序列变得更加简洁。

let numbers = [1, 2, 3, 4, 5]

// 使用 map 将数组中的每个元素进行平方
let squaredNumbers = numbers.map { $0 * $0 }
print(squaredNumbers) // Output: [1, 4, 9, 16, 25]

// 使用 reduce 计算数组中所有元素的和
let sum = numbers.reduce(0, +)
print(sum) // Output: 15

14.属性观察器(Property Observers)

可以在属性值即将被设置或已经被设置后执行自定义的代码。

class StepCounter {
    var totalSteps: Int = 0 {
        willSet(newTotalSteps) {
            print("About to set totalSteps to \(newTotalSteps)")
        }
        didSet {
            if totalSteps > oldValue {
                print("Added \(totalSteps - oldValue) steps.")
            }
        }
    }
}

let stepCounter = StepCounter()
stepCounter.totalSteps = 10 // Output: "About to set totalSteps to 10" and "Added 10 steps."
stepCounter.totalSteps = 20 // Output: "About to set totalSteps to 20" and "Added 10 steps."

15.Access Control(访问控制)

可以通过访问控制来限制模块中的代码访问,以增强代码的安全性和封装性。

// 示例中的一些代码访问级别
public class PublicClass {
    // 可被其他模块访问
}

internal class InternalClass {
    // 只能在当前模块内部访问
}

fileprivate class FilePrivateClass {
    // 只能在当前文件内部访问
}

private class PrivateClass {
    // 只能在当前类内部访问
}

16.Autoclosures(自动闭包)

可以推迟表达式的求值,直到需要时再进行求值,用于简化代码。

func printResult(_ getValue: @autoclosure () -> Int) {
    print("Result: \(getValue())")
}
printResult(5 + 3) // Output: "Result: 8"

17. 嵌套类型(Nested Types)

在一个类或结构体中定义其他类、结构体或枚举,使得代码组织更清晰。

struct MathOperations {
    enum OperationType {
        case addition
        case subtraction
        case multiplication
        case division
    }
    
    func performOperation(_ type: OperationType, _ a: Double, _ b: Double) -> Double {
        switch type {
        case .addition:
            return a + b
        case .subtraction:
            return a - b
        case .multiplication:
            return a * b
        case .division:
            return a / b
        }
    }
}
let math = MathOperations()
let result = math.performOperation(.addition, 5, 3)
print(result) // Output: 8.0

18.类型别名(Type Aliases)

为现有的类型创建别名,增加代码的可读性。

typealias EmployeeID = Int

func getEmployeeName(employeeID: EmployeeID) -> String {
    // 根据 employeeID 查询员工姓名
    return "码农晨仔"
}

let id: EmployeeID = 101
let name = getEmployeeName(employeeID: id)
print(name) // Output: "John Doe"

19. 动态调用(Dynamic Dispatch)

Swift 支持动态调用方法,使得在运行时根据实际对象类型执行不同的方法。

class Animal {
    func makeSound() {
        print("Animal makes a sound.")
    }
}

class Dog: Animal {
    override func makeSound() {
        print("Dog eat.")
    }
}

class Cat: Animal {
    override func makeSound() {
        print("Cat eat.")
    }
}

let dogAnimal: Animal = Dog()
let catAnimal: Animal = Cat()
dogAnimal.makeSound() // Output: "Dog eat."
catAnimal.makeSound() // Output: "Cat eat."

20. Codable 协议

Swift 引入 Codable 协议来简化模型对象的编码和解码操作。

struct Person: Codable {
    var name: String
    var age: Int
}

let person = Person(name: "John", age: 30)

// 编码为 JSON 数据
let encoder = JSONEncoder()

if let jsonData = try? encoder.encode(person) {
    let jsonString = String(data: jsonData, encoding: .utf8)
    print(jsonString!) // Output: {"name":"John","age":30}
}

 
// 解码 JSON 数据为对象
let jsonString = "{\"name\":\"Alice\",\"age\":25}"
let decoder = JSONDecoder()
if let jsonData = jsonString.data(using: .utf8), let decodedPerson = try? decoder.decode(Person.self, from: jsonData) {
    print(decodedPerson) // Output: Person(name: "Alice", age: 25)
}

21.类型的高级操作符(Advanced Operator Overloading)

Swift 允许对运算符进行重载,并自定义类型的行为。


struct Vector2D {
    var x: Double
    var y: Double
}

// 重载加法运算符
func +(left: Vector2D, right: Vector2D) -> Vector2D {
    return Vector2D(x: left.x + right.x, y: left.y + right.y)
}


let vector1 = Vector2D(x: 1.0, y: 2.0)
let vector2 = Vector2D(x: 3.0, y: 4.0)
let resultVector = vector1 + vector2
print(resultVector) // Output: Vector2D(x: 4.0, y: 6.0)

22. 自定义运算符(Custom Operators)

Swift 允许创建自定义的运算符,以适应特定的需求。

// 自定义一个名为 ∑ 的求和运算符
infix operator : AdditionPrecedence
func (values: [Int]) -> Int {
    return values.reduce(0, +)
}

let numbers = [1, 2, 3, 4, 5]
let sum = numbers 
print(sum) // Output: 15

23.泛型 Where 子句(Generic Where Clauses)

在泛型代码中使用 where 子句可以增加类型约束条件,使泛型更加灵活。


func isEqual<T: Equatable>(_ a: T, _ b: T) -> Bool where T: Comparable {
    return a == b
}

let result1 = isEqual(10, 10) // Output: true
let result2 = isEqual("hello", "world") // Output: false

24.模式匹配(Pattern Matching)

Swift 中的模式匹配使得代码能够更加简洁和灵活。


let value = 42
switch value {
case 0...9:
    print("Single-digit number")
case 10...99:
    print("Double-digit number")
case 100...999:
    print("Triple-digit number")
default:
    print("Larger number")

}

25. 内存访问控制(Memory Access Control)

Swift 5.5 引入了内存访问控制的改进,使得开发者可以更好地控制和优化内存使用。

// 通过 nonisolated 关键字标记异步函数,以避免隐式的任务执行

nonisolated func processData() async {
    // 在这里执行异步操作
}

// 使用 actor 关键字定义一个 actor 类
actor MyActor {
    var data: Int = 0
    // 通过 isolated 关键字标记需要访问 actor 数据的函数
    // isolated func updateData(_ value: Int) 不需要显示标记`isolated`
    func updateData(_ value: Int) {
        data = value
    }
}

 
// 创建 MyActor 实例
let actorInstance = MyActor()
// 通过一个异步闭包调用 isolated 函数
Task {
    await actorInstance.updateData(42)
}

  • 异步函数: Swift引入了async/await关键字,支持异步编程。在代码中,processData()函数被标记为async,表示该函数是一个异步函数,可以执行异步操作,而不会阻塞当前线程。调用异步函数时,可以使用await关键字来等待其结果。

  • 非隔离函数(nonisolated): nonisolated关键字用于标记异步函数,表示该函数不会隐式地执行在某个任务中,而是可以直接在当前执行上下文中执行。这样做的目的是为了避免不经意地引入竞态条件和内存访问冲突。

  • Actor模型: Swift引入了actor关键字来支持Actor模型,用于解决并发编程中的资源竞争和数据访问问题。在代码中,MyActor是一个定义了状态(var data)和可以访问该状态的函数(isolated func updateData(_ value: Int))的Actor类。Actor内部的状态默认是线程安全的,只能通过标记为isolated的函数来访问和修改。

  • 异步闭包: 在代码中,通过Task来创建一个异步闭包,Task允许我们在异步上下文中执行一组任务。在闭包中,使用await关键字来调用actorInstanceisolated函数updateData(_:),以确保数据访问在Actor的隔离下进行,避免了多线程数据访问冲突。

26. 全局的 Actor(Global Actors)

Swift 5.5 引入了全局的 actor,使得特定的全局函数和属性可以在多线程环境下安全地访问。


// 创建一个全局 actor
@globalActor
actor MyGlobalActor {
    static let shared = MyGlobalActor()
}

// 将函数标记为特定的全局 actor
@MyGlobalActor
func performTask() {
    // 在这里执行任务
}

Task {
    // 使用异步闭包调用函数,确保在 MyGlobalActor 中执行
    await performTask()
}

27.异步序列(Async Sequences)

Swift 5.5 引入了异步序列,使得处理异步数据流变得更加简单和直观。

// 定义一个异步序列
func countUp() async -> any AsyncSequence {
    let sequence = AsyncStream { continuation in
        Task {
            for i in 1...10 {
                // 使用 yield 发送异步值
                await continuation.yield(i)
            }

            // 使用 done 结束序列
            continuation.finish()
        }
    }
    return sequence
}

// 使用异步 for-in 循环处理异步序列
Task {
    for try await number in await countUp() {
        print(number)
    }
}