1. 基础语法:可选类型(Optional)

题目: 什么是 Optional?为什么需要 Optional?如何安全解包?
答案:

  • 定义:Optional 是 Swift 特有的类型,用于表示 “值可能存在(非 nil)或不存在(nil)”,语法上通过?声明(如var name: String?)。
  • 必要性:解决 Objective-C 中 “空指针异常(nil 调用方法崩溃)” 问题,强制开发者显式处理 “值可能为空” 的场景,编译期避免潜在崩溃。
  • 安全解包方式:
    • 可选绑定(Optional Binding):if let unwrappedName = name { ... } 或 guard let unwrappedName = name else { return }(推荐,提前退出);
    • 强制解包(!):let unwrappedName = name!(危险,nil 时崩溃,仅确定非空时使用);
    • 隐式解包可选类型(Implicitly Unwrapped Optional):var name: String!(声明时假定非空,适合初始化后必赋值的场景,如 IBOutlet);
    • 空合运算符(Nil-Coalescing):let unwrappedName = name ?? "default"(nil 时使用默认值)。

2. 数据类型:Struct 与 Class 的区别

题目: Swift 中 Struct 和 Class 有哪些核心区别?分别适用于什么场景?
答案:
Struct:用于存储简单数据(如模型、坐标CGPoint)、强调值相等的场景(如Int、String本质是结构体);
Class:用于需要继承、共享状态(如视图控制器UIViewController)、复杂逻辑的场景。

维度 Struct(结构体) Class(类)
类型性质 值类型(Value Type) 引用类型(Reference Type)
内存存储 栈上分配(或嵌入宿主内存) 堆上分配
赋值 / 传递行为 复制值(深拷贝) 复制引用(浅拷贝)
继承 不支持继承 支持单继承
析构函数 不支持 deinit 支持 deinit(析构)
身份标识(===) 无(值相等用==) 有(引用相等用===)

3. 闭包(Closure):循环引用与捕获列表

题目: Swift 闭包中为什么会产生循环引用?如何解决?请举例说明。
答案:

  • 循环引用原因:闭包会默认强引用其捕获的外部变量 / 常量。若闭包被一个对象(如self)强引用,且闭包内部又强引用该对象(如self),则形成 “对象→闭包→对象” 的强引用循环,导致两者都无法释放。
  • 解决方式:通过捕获列表(Capture List) 显式声明对捕获变量的引用方式(weak或unowned):
    • weak:弱引用,捕获的对象可能为 nil(需用可选类型),适用于对象生命周期可能短于闭包的场景;
    • unowned:无主引用,捕获的对象一定非 nil(无需可选类型),适用于对象生命周期与闭包一致的场景(如闭包作为对象的属性,且对象不提前释放)。
class Person {
    var name: String
    var closure: (() -> Void)?
    
    init(name: String) {
        self.name = name
    }
    
    deinit {
        print("Person deinit")
    }
}

// 错误示例:循环引用(self → closure → self)
let person = Person(name: "Alice")
person.closure = {
    print(person.name) // 闭包强引用person
}

// 正确示例1:weak(person可能为nil,需解包)
person.closure = { [weak self] in
    guard let self = self else { return } // 安全解包
    print(self.name)
}

// 正确示例2:unowned(确定person不会提前释放)
person.closure = { [unowned self] in
    print(self.name) // 无需解包,若self为nil会崩溃
}

4. 内存管理:ARC 与引用类型

题目: Swift 的 ARC(自动引用计数)如何工作?与 Objective-C 的 ARC 有何异同?
答案:

  • ARC 工作原理:ARC 通过跟踪对象的 “强引用” 数量管理内存:
    当对象被强引用时,引用计数 + 1;
    强引用解除时,引用计数 - 1;
    引用计数为 0 时,对象被销毁,释放内存。
  • 与 Objective-C ARC 的异同:
    • 相同点:核心机制一致(强引用计数管理),都需手动处理循环引用(weak/unowned)。
    • 不同点:
      Swift 中weak变量必须是可选类型(var obj: Type?),而 Objective-C 中__weak变量可直接声明;
      Swift 引入unowned(对应 Objective-C 的__unsafe_unretained),但更安全(编译期检查非空场景);
      Swift 的值类型(Struct/Enum)不适用 ARC(栈上分配,无需引用计数),而 Objective-C 几乎全是引用类型。

5. 高级特性:泛型(Generics)

题目: 什么是泛型?请举例说明泛型在 Swift 中的应用场景和优势。
答案:

  • 定义:泛型是一种 “类型抽象” 机制,允许函数、结构体、类、协议在不指定具体类型的情况下定义,支持多种类型复用同一套逻辑。
  • 应用场景:
    通用数据结构(如数组Array、字典Dictionary<K, V>);
    通用算法(如交换两个值、排序);
    协议关联类型(如Collection协议的Element)。
  • 优势:
    代码复用:一套逻辑支持多种类型,减少重复代码;
    类型安全:编译期检查类型匹配,避免运行时错误;
    灵活性:不限制具体类型,同时保证类型约束。
  • 示例:实现一个通用的 “交换两个值” 的函数:
// 泛型函数:T为类型占位符,支持任意类型
func swap<T>(_ a: inout T, _ b: inout T) {
    let temp = a
    a = b
    b = temp
}

// 应用于Int
var x = 10, y = 20
swap(&x, &y) // x=20, y=10

// 应用于String
var s1 = "hello", s2 = "world"
swap(&s1, &s2) // s1="world", s2="hello"

6. 异步编程:async/await(Swift 5.5+)

题目: Swift 的 async/await 解决了什么问题?与传统的闭包回调相比有何优势?
答案:

  • 解决的问题:传统闭包回调实现异步逻辑时,容易产生 “回调地狱(Callback Hell)”(多层嵌套导致代码可读性差、错误处理复杂)。async/await 用同步的代码风格编写异步逻辑,扁平化代码结构。
  • 优势:
    代码线性化:避免嵌套,逻辑清晰;
    错误处理简单:可通过try/catch统一处理,替代闭包中的错误回调;
    可组合性:支持async let并发执行多个异步任务。
  • 示例:异步获取用户信息并打印:
// 异步函数:获取用户ID(模拟网络请求)
func fetchUserID() async -> Int {
    try? await Task.sleep(nanoseconds: 1_000_000_000) // 模拟1秒延迟
    return 1001
}

// 异步函数:通过ID获取用户名
func fetchUserName(for id: Int) async -> String {
    try? await Task.sleep(nanoseconds: 1_000_000_000)
    return "User_\(id)"
}

// 主逻辑:用async/await调用
func printUserName() async {
    let userId = await fetchUserID() // 等待第一个异步任务
    let userName = await fetchUserName(for: userId) // 等待第二个异步任务
    print("用户名:\(userName)")
}

// 启动异步任务(需在Task中)
Task {
    await printUserName() // 输出:用户名:User_1001
}

7. 与 Objective-C 混编

题目: Swift 中如何调用 Objective-C 代码?Objective-C 如何调用 Swift 代码?需要注意哪些问题?
答案:

  • Swift 调用 Objective-C:
    创建桥接头文件(ProjectName-Bridging-Header.h);
    在桥接头文件中导入需要调用的 Objective-C 头文件(如#import “OCClass.h”);
    Swift 中直接使用 Objective-C 类(如let obj = OCClass())。
  • Objective-C 调用 Swift:
    确保Build Settings中Defines Module设为YES;
    Swift 类 / 方法需用@objc修饰(暴露给 Objective-C);
    Objective-C 中导入自动生成的头文件(#import “ProjectName-Swift.h”),直接使用 Swift 类。
    注意事项:
    Swift 特有类型(如Optional、Struct、Enum)在 Objective-C 中可能无法直接使用(需用@objc适配);
    闭包在 Objective-C 中会转为block,需用@escaping标记逃逸闭包;
    协议需用@objc修饰才能被 Objective-C 遵循。
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐