Hi~
Hi~
文章目录
  1. 一、Struct 与 Class 深度对比
    1. 1. 核心区别
    2. 2. 初始化注意事项
  2. 二、Codable 协议实战
    1. 1. Class 支持 Codable
    2. 2. 字段兼容技巧
  3. 三、Optional 本质剖析
  4. 四、多线程编程
    1. 1. GCD 核心概念
    2. 2. async/await (Swift Concurrency)
  5. 五、Swift 核心语法
    1. 1. Protocol 高级用法
    2. 2. 泛型约束
    3. 3. 闭包管理
  6. 六、内存管理(ARC)
    1. 1. 循环引用解决方案
  7. 七、响应式编程框架
    1. 1. Combine 核心组件
    2. 2. RxSwift 核心操作符
  8. 高频进阶面试题
  • 📌 iOS 基础面试题(Objective-C + Swift)
  • 一、Objective-C 基础
    1. 1. 内存管理
    2. 2. Runtime
    3. 3. 多线程
    4. 4. 设计模式
  • 二、Swift 基础
    1. 1. struct vs class
    2. 2. Optional
    3. 3. 协议 & 泛型
    4. 4. 闭包
    5. 5. 多线程(Swift)
    6. 6. Codable
    7. 7. 内存管理(Swift)
    8. 8. 响应式编程
  • 三、iOS 开发基础
    1. 1. UI & 动画
    2. 2. 网络
    3. 3. 数据库
    4. 4. 性能优化
    5. 5. 架构 & 设计模式
  • 📌 高频 Swift 面试题
    1. 1. struct vs class
    2. 2. Codable
    3. 3. 多线程
    4. 4. 内存管理
    5. 5. 响应式编程
  • 📌 总结
    1. 一、语言深度与底层原理
      1. 1. Swift 高阶特性
      2. 2. Objective-C 底层
    2. 二、系统机制与框架原理
      1. 1. UIKit 与渲染
      2. 2. 网络与安全
      3. 3. 数据库与持久化
    3. 三、架构设计与模式
      1. 1. 架构演进
      2. 2. 设计模式实战
    4. 四、性能优化与调试
      1. 1. 性能调优
      2. 2. 调试与逆向
    5. 五、综合场景与前沿技术
      1. 1. 复杂场景设计
      2. 2. 前沿技术
    6. 六、实战编码题
    7. 考察重点
    8. 1. 基本结构
      1. 示例代码
    9. 2. Getter 和 Setter 的生命周期
      1. (1) 计算属性(Computed Property)
      2. (2) 存储属性(Stored Property)
    10. 3. 观察器(willSet 和 didSet)的生命周期
      1. 调用顺序
      2. 示例流程
    11. 4. 关键区别与作用
    12. 5. 高级场景与注意事项
      1. (1) 初始化阶段不触发观察器
      2. (2) 避免在 didSet 中重复触发修改
      3. (3) 计算属性与观察器的互斥
      4. (4) 性能影响
    13. 6. 综合示例
    14. 总结
  • 🧱 一、Struct 与 Class 的区别
    1. 结构体适用场景
  • 🔧 二、Struct 与 Class 初始化注意事项
    1. Struct 初始化
    2. Class 初始化
  • 🧬 三、Class 是否可以遵守 Codable 协议?
  • 🧩 四、如何处理 Codable 字段名/类型不一致
    1. ✅ 方法一:使用 CodingKeys 自定义字段映射
    2. ✅ 方法二:字段类型不一致,手动 decode/encode
  • ❓ 五、Optional 的本质是什么?
  • 🚦 六、Swift 多线程编程
    1. 1. GCD(Grand Central Dispatch)
      1. 异步队列 & 同步队列
      2. 延迟执行
      3. 并发队列 & 串行队列
      4. DispatchGroup
    2. 2. Swift 5.5+ async/await(推荐)
      1. 并发执行任务
      2. TaskGroup 使用
  • 🧠 七、补充高级面试题建议
    1. ❓ Swift 中 enum 是值类型还是引用类型?
    2. ❓ Swift 中 mutating 关键字作用?
    3. ❓ Swift 如何防止 retain cycle?
  • 🧩 一、Protocol 协议相关面试题
    1. ❓ Protocol 和 Class/Struct 有什么不同?
    2. ❓ 协议中的 associatedtype 有什么作用?
    3. ❓ Protocol Extension 有什么用?
  • 🧬 二、泛型(Generics)
    1. ❓ 如何写一个泛型函数?
    2. ❓ 泛型约束写法有哪些?
  • 🧠 三、闭包(Closure)
    1. ❓ 闭包与函数的区别?
    2. ❓ 闭包的语法简化过程?
    3. ❓ 如何避免闭包导致的循环引用?
  • 📚 四、高阶函数面试题
    1. 常见高阶函数总结
    2. 面试示例题
  • 🔁 五、Combine 基础面试题
    1. ❓ Combine 的核心组件有哪些?
    2. ❓ 示例:使用 Combine 实现双向绑定
  • 🌊 六、RxSwift 基础面试题
    1. ❓ RxSwift 与 Combine 的异同?
    2. ❓ 如何创建 Observable?
  • 🗑️ 七、ARC 内存管理面试题
    1. ❓ Swift 的 ARC 如何工作?
    2. ❓ strong / weak / unowned 区别?
    3. ❓ 如何解决循环引用(Retain Cycle)?
  • 🧪 Bonus:Swift 面试设计题
  • iOS 面试题大全(Objective-C + Swift)
    1. 一、语言基础
      1. Objective-C
      2. Swift
    2. 二、内存管理
    3. 三、多线程与并发
      1. GCD
      2. OperationQueue
      3. Swift async/await
    4. 四、网络编程
    5. 五、数据库与持久化
    6. 六、设计模式
    7. 七、常用框架
      1. Combine
      2. RxSwift
    8. 八、高阶 Swift 语法
    9. 九、其他基础知识
    10. 十、Swift 进阶机制
    11. 十一、性能优化与调试
    12. 十二、测试与 CI/CD
    13. 十三、iOS 安全性
    14. 一、Getter 与 Setter(计算属性)
      1. 生命周期:
    15. 二、willSet 与 didSet(存储属性观察者)
      1. 生命周期和执行顺序:
      2. 特点和规则:
    16. 三、get/set 与 willSet/didSet 的本质区别
    17. 四、实践建议
      1. 1. 基本结构
        1. 示例代码
      2. 2. Getter 和 Setter 的生命周期
        1. (1) 计算属性(Computed Property)
        2. (2) 存储属性(Stored Property)
      3. 3. 观察器(willSet 和 didSet)的生命周期
        1. 调用顺序
        2. 示例流程
      4. 4. 关键区别与作用
      5. 5. 高级场景与注意事项
        1. (1) 初始化阶段不触发观察器
        2. (2) 避免在 didSet 中重复触发修改
        3. (3) 计算属性与观察器的互斥
        4. (4) 性能影响
      6. 6. 综合示例
      7. 总结
  • iOS 基础面试题

    以下是一套系统的 Swift 面试题整理,涵盖核心语法、多线程编程、内存管理及主流框架,问题按模块分类并附详细解答:


    一、Struct 与 Class 深度对比

    1. 核心区别

    • 值类型 vs 引用类型struct 是值类型(栈内存),class 是引用类型(堆内存)
    • 继承class 支持继承,struct 不支持
    • 内存管理class 需要手动处理引用计数(ARC),struct 无需
    • 线程安全struct 天然线程安全(值拷贝),class 需自行同步
    • 性能struct 在小数据量时更高效(无堆分配和引用计数开销)

    2. 初始化注意事项

    • Struct
      • 自动生成成员初始化器(除非自定义 init
        struct Point {
        var x: Int
        var y: Int
        // 自动生成 init(x: Int, y: Int)
        }
    • Class
      • 必须为所有非可选属性赋初值(通过默认值或 init
      • 子类必须先初始化自身属性,再调用 super.init
        class Person {
        var name: String
        init(name: String) { self.name = name }
        }

    二、Codable 协议实战

    1. Class 支持 Codable

    • 可以:只要所有存储属性均遵守 Codable
      class User: Codable {
      var id: Int
      var name: String
      }

    2. 字段兼容技巧

    • 字段名映射:使用 CodingKeys 枚举
      struct Book: Codable {
      var title: String
      var price: Double

      enum CodingKeys: String, CodingKey {
      case title = "book_title"
      case price
      }
      }
    • 类型兼容:自定义 init(from:) 处理类型转换
      struct Product: Codable {
      var id: String

      init(from decoder: Decoder) throws {
      let container = try decoder.container(keyedBy: CodingKeys.self)
      // 兼容接口返回 id 为 Int 或 String
      if let intId = try? container.decode(Int.self, forKey: .id) {
      id = String(intId)
      } else {
      id = try container.decode(String.self, forKey: .id)
      }
      }
      }

    三、Optional 本质剖析

    • 本质Optional 是标准库中的泛型枚举
      public enum Optional<Wrapped> {
      case none
      case some(Wrapped)
      }
    • 底层行为:编译器通过语法糖(?!)简化操作,实际仍走枚举模式匹配

    四、多线程编程

    1. GCD 核心概念

    • 队列类型
      • Serial(串行):DispatchQueue(label: "serial")
      • Concurrent(并行):DispatchQueue(label: "concurrent", attributes: .concurrent)
    • 常见操作
      DispatchQueue.global(qos: .background).async {
      // 后台任务
      DispatchQueue.main.async { /* 更新UI */ }
      }

    2. async/await (Swift Concurrency)

    • 关键语法
      func fetchData() async throws -> Data {
      let (data, _) = try await URLSession.shared.data(from: url)
      return data
      }
    • Task 使用
      Task {
      let result = await someAsyncFunction()
      print(result)
      }

    五、Swift 核心语法

    1. Protocol 高级用法

    • 关联类型(Associated Types):
      protocol Container {
      associatedtype Item
      mutating func append(_ item: Item)
      }
    • 协议组合func foo(bar: SomeProtocol & AnotherProtocol)

    2. 泛型约束

    • Where 子句
      func process<T>(_ value: T) where T: Numeric {
      print(value + value)
      }

    3. 闭包管理

    • 逃逸闭包:标记为 @escaping 需注意循环引用
      class Manager {
      var completion: (() -> Void)?

      func setup(completion: @escaping () -> Void) {
      self.completion = completion
      }
      }

    六、内存管理(ARC)

    1. 循环引用解决方案

    • weakweak var delegate: SomeDelegate?
    • unownedunowned let owner: SomeClass(无主引用,必须确保对象存活)
    • 捕获列表
      lazy var closure: () -> Void = { [weak self] in
      guard let self = self else { return }
      self.doSomething()
      }

    七、响应式编程框架

    1. Combine 核心组件

    • Publisher/Subscriber 模式:
      [1, 2, 3].publisher
      .sink { print($0) }

    2. RxSwift 核心操作符

    • 常用链式调用
      Observable.of(1, 2, 3)
      .filter { $0 > 1 }
      .map { $0 * 2 }
      .subscribe(onNext: { print($0) })

    高频进阶面试题

    1. 为什么 Swift 推荐多用 Struct?

      • 值类型线程安全、无引用计数开销、适合不可变数据场景
    2. 如何实现一个线程安全的单例?

      class Singleton {
      static let shared = Singleton()
      private init() {}
      }
    3. Protocol Extension 如何实现默认实现?

      protocol Drawable { func draw() }
      extension Drawable {
      func draw() { print("Default implementation") }
      }
    4. @MainActor 的作用是什么?

      • 确保代码在主线程执行,替代 DispatchQueue.main.async

    以下是一份全面覆盖 Objective-CSwift 的 iOS 基础面试题,涵盖 内存管理、多线程、设计模式、网络、数据库、框架 等核心领域,并针对 Swift 语法(如 struct/classCodableOptional、多线程、闭包、响应式编程等)进行深入整理。


    📌 iOS 基础面试题(Objective-C + Swift)


    一、Objective-C 基础

    1. 内存管理

    1. 什么是 ARC?MRC 和 ARC 的区别?
    2. strongweakassigncopyunsafe_unretained 的区别?
    3. 循环引用的原因及解决方案(weakblock 弱引用)?
    4. autoreleasepool 的作用?使用场景?
    5. dealloc 方法的作用?能否调用 [super dealloc]

    2. Runtime

    1. 什么是 Runtime?动态特性有哪些?
    2. objc_msgSend 的作用?消息转发流程(resolveInstanceMethodforwardingTargetForSelectormethodSignatureForSelector)?
    3. classmeta-class 的区别?isKindOfClassisMemberOfClass 的区别?
    4. method swizzling 是什么?如何实现?有哪些坑?
    5. KVO 的实现原理?如何手动触发 KVO?

    3. 多线程

    1. GCD 的队列类型(serialconcurrentmainglobal)?
    2. dispatch_barrier_async 的作用?
    3. NSOperation 和 GCD 的区别?NSOperationQueue 如何控制并发数?
    4. @synchronized 的原理?它和 NSLockdispatch_semaphore 的区别?
    5. 多线程常见问题(死锁、线程安全、优先级反转)?

    4. 设计模式

    1. MVC、MVP、MVVM 的区别?iOS 中 MVC 的问题?
    2. 单例模式的实现(线程安全)?
    3. Delegate 和 Notification 的区别?
    4. 工厂模式、观察者模式、责任链模式的应用场景?
    5. KVC 和 KVO 的使用场景?

    二、Swift 基础

    1. struct vs class

    1. structclass 的核心区别(值类型 vs 引用类型、内存管理、继承等)?
    2. struct 自动生成 initclass 必须手动初始化?
    3. mutating 关键字的作用?
    4. final 关键字的作用?

    2. Optional

    1. Optional 的本质是什么?(enum.none.some(Wrapped)
    2. ??if letguard letoptional chaining 的区别?
    3. @unwrapped 和隐式解包(String!)的区别?

    3. 协议 & 泛型

    1. Protocolassociatedtype 是什么?如何约束?
    2. where 子句在泛型中的作用?
    3. Selfself 的区别?

    4. 闭包

    1. 逃逸闭包(@escaping)和非逃逸闭包的区别?
    2. [weak self][unowned self] 的区别?
    3. lazy var + 闭包初始化?

    5. 多线程(Swift)

    1. GCD 在 Swift 中的使用(DispatchQueueDispatchGroup)?
    2. async/awaitTask 的使用?
    3. @MainActor 的作用?

    6. Codable

    1. class 可以遵守 Codable 吗?如何实现?
    2. 如何用 CodingKeys 映射 JSON 字段?
    3. 如何处理接口返回的 Int/String 兼容问题?

    7. 内存管理(Swift)

    1. weakunownedstrong 的区别?
    2. 循环引用在 Swift 中的常见场景及解决方案?
    3. deinit 的作用?

    8. 响应式编程

    1. Combine 的核心组件(PublisherSubscriberSubject)?
    2. RxSwift 的常见操作符(mapfilterflatMap)?
    3. ObservableFuture 的区别?

    三、iOS 开发基础

    1. UI & 动画

    1. UIViewCALayer 的区别?
    2. frameboundscenter 的区别?
    3. Auto Layout 的原理?intrinsicContentSize 的作用?
    4. UIView.animateCore Animation 的区别?
    5. 离屏渲染(cornerRadiusshadow)的优化?

    2. 网络

    1. HTTP 和 HTTPS 的区别?HTTPS 的握手过程?
    2. URLSession 的使用(dataTaskuploadTaskdownloadTask)?
    3. Alamofire 的核心实现?
    4. CookieSession 的区别?

    3. 数据库

    1. Core DataRealm 的区别?
    2. SQLite 的增删改查(FMDB 的使用)?
    3. @FetchRequest 在 SwiftUI 中的作用?

    4. 性能优化

    1. 卡顿检测(CADisplayLinkInstruments)?
    2. 内存泄漏检测(LeaksMLeaksFinder)?
    3. 图片加载优化(SDWebImage 的缓存策略)?

    5. 架构 & 设计模式

    1. 如何设计一个网络层?
    2. 如何实现一个路由(URL Router)?
    3. 依赖注入(DI)的实现方式?

    📌 高频 Swift 面试题

    1. struct vs class

    • 值类型 vs 引用类型
    • 内存分配(栈 vs 堆)
    • 线程安全性
    • mutating 关键字的作用

    2. Codable

    • class 如何遵守 Codable
    • CodingKeys 的使用
    • 处理接口字段不一致(Int/String 兼容)

    3. 多线程

    • GCD(DispatchQueueDispatchGroup
    • async/await 的使用
    • @MainActor 的作用

    4. 内存管理

    • weak vs unowned
    • 循环引用的解决方案

    5. 响应式编程

    • Combine 的核心概念
    • RxSwift 的常见操作符

    📌 总结

    • Objective-C:重点在 内存管理(ARC)、Runtime、多线程(GCD)、设计模式(Delegate、KVO)
    • Swift:重点在 struct/classOptionalCodable、多线程(async/await)、内存管理
    • iOS 基础UI(Auto Layout)、网络(URLSession)、数据库(Core Data)、性能优化

    以下是为资深 iOS 开发工程师设计的高阶综合面试题,涵盖底层原理、架构设计、性能优化及前沿技术,分为 语言深度系统机制架构设计性能优化综合场景 五大模块:


    一、语言深度与底层原理

    1. Swift 高阶特性

    1. 泛型与协议

      • 如何设计一个支持泛型缓存的 Repository 模式?
      • associatedtypesomeany 关键字的区别?Swift 5.7 的不透明类型优化了什么?
      • 为什么 Protocol 不能直接作为类型使用?如何用类型擦除(Type Erasure)解决?
    2. 内存管理

      • Swift 的 unownedweak 在底层是如何实现的?何时会导致野指针?
      • withUnsafeByteswithMemoryRebound 的使用场景?如何安全操作指针?
    3. 并发模型

      • actor 的隔离机制如何实现?与 @MainActor 的线程调度差异?
      • Sendable 协议的作用?如何让自定义类型支持跨线程传递?

    2. Objective-C 底层

    1. Runtime 进阶

      • objc_msgSend 的快速查找(缓存)和慢速查找(方法列表)流程?
      • 如何通过 NSInvocation 动态调用任意参数的方法?
      • class_ro_tclass_rw_t 的区别?方法列表的动态扩展如何实现?
    2. 内存管理

      • NSCacheNSDictionary 的内存策略差异?如何实现 LRU 缓存?
      • __weak 变量的底层实现(SideTable 结构)?

    二、系统机制与框架原理

    1. UIKit 与渲染

    1. 渲染流水线

      • Core Animation 的 CALayer 提交到 GPU 的完整流程?
      • 离屏渲染(Offscreen Rendering)的底层触发条件及优化方案?
    2. 事件传递

      • hitTest:withEvent:pointInside:withEvent: 的调用链路?如何实现穿透点击?

    2. 网络与安全

    1. HTTP/2 与 QUIC

      • HTTP/2 的多路复用如何提升性能?与 QUIC 协议的差异?
      • iOS 如何实现 TLS 1.3 的 0-RTT 加速?
    2. 长连接优化

      • 如何设计一个支持断线重连、心跳保活的 WebSocket 客户端?

    3. 数据库与持久化

    1. Core Data 进阶

      • 如何优化 NSFetchedResultsController 在大数据量下的性能?
      • 多线程环境下 NSManagedObjectContext 的合并策略(MergePolicy)?
    2. SQLite 优化

      • WAL(Write-Ahead Logging)模式的工作原理?如何避免 SQLITE_BUSY 错误?

    三、架构设计与模式

    1. 架构演进

    1. 从 MVC 到 MVVM

      • 如何在不引入 Reactive 框架的情况下实现 MVVM 的数据绑定?
      • ViewModel 如何避免持有 View 导致的循环引用?
    2. 模块化与组件化

      • 如何设计一个支持动态插拔的模块化架构(如路由 + Protocol)?
      • CocoaPodsSwift Package Manager 的二进制化方案?

    2. 设计模式实战

    1. 响应式编程

      • Combine 的 Publisher 冷热信号差异?如何实现自定义 Publisher
      • RxSwift 的 flatMapflatMapLatest 在搜索场景中的应用?
    2. 依赖注入

      • 如何利用 Property Wrapper 实现类型安全的 DI 容器?

    四、性能优化与调试

    1. 性能调优

    1. 启动优化

      • dyld 动态链接的耗时如何测量?如何减少 __DATA 段的修复时间?
      • +load+initialize 的优化策略?
    2. 内存优化

      • 如何通过 VM Tracker 分析内存碎片问题?
      • NSCachetotalCostLimit 策略与内存警告的关系?

    2. 调试与逆向

    1. LLDB 高阶

      • 如何通过 image lookup -a 定位野指针崩溃?
      • 动态修改 UIView 属性的 LLDB 命令?
    2. 逆向分析

      • 如何通过 Hopper 静态分析第三方库的私有 API 调用?

    五、综合场景与前沿技术

    1. 复杂场景设计

    1. 跨平台方案

      • SwiftUI 与 Flutter 的渲染引擎差异?如何实现高性能的跨平台列表?
    2. 大文件传输

      • 如何设计一个支持断点续传、分块校验的文件上传服务?

    2. 前沿技术

    1. 机器学习

      • Core ML 的模型加密与动态更新方案?
    2. AR 与 Metal

      • 如何通过 Metal 实现自定义的 AR 渲染管线?

    六、实战编码题

    1. 实现线程安全的 LRU 缓存

      final class LRUCache<Key: Hashable, Value> {
      private let lock = NSLock()
      private let capacity: Int
      private var cache: [Key: Value] = [:]
      private var order: [Key] = []

      init(capacity: Int) { self.capacity = capacity }

      func get(_ key: Key) -> Value? {
      lock.lock()
      defer { lock.unlock() }
      guard let value = cache[key] else { return nil }
      order.removeAll { $0 == key }
      order.append(key)
      return value
      }

      func set(_ key: Key, value: Value) {
      lock.lock()
      defer { lock.unlock() }
      if cache[key] == nil && cache.count >= capacity {
      let removedKey = order.removeFirst()
      cache[removedKey] = nil
      }
      cache[key] = value
      order.append(key)
      }
      }
    2. 基于 Combine 实现防抖搜索

      import Combine

      class SearchViewModel {
      @Published var query: String = ""
      private var cancellables = Set<AnyCancellable>()

      init() {
      $query
      .debounce(for: .milliseconds(300), scheduler: RunLoop.main)
      .removeDuplicates()
      .sink { [weak self] query in
      self?.performSearch(query: query)
      }
      .store(in: &cancellables)
      }

      private func performSearch(query: String) {
      print("Searching for: \(query)")
      }
      }

    考察重点

    • 深度:是否理解语言特性背后的底层机制(如 Swift 的 Optional 枚举、OC 的消息转发)。
    • 架构能力:能否设计高扩展、低耦合的模块化方案。
    • 性能敏感度:对渲染管线、内存管理等系统级优化的实践经验。
    • 技术前瞻性:对 Combine、Swift Concurrency 等新技术的落地思考。

    在 Swift 中,属性的 gettersetter 及其观察器(willSetdidSet)的生命周期和调用顺序是属性管理的核心机制。以下是它们的详细解析:


    1. 基本结构

    Swift 中的属性可以分为:

    • 存储属性(Stored Property):直接存储值,可附加观察器。
    • 计算属性(Computed Property):通过 getter/setter 动态计算值,不可附加观察器。

    示例代码

    struct Person {
    // 存储属性 + 观察器
    var name: String {
    willSet { print("willSet: \(name)\(newValue)") }
    didSet { print("didSet: \(oldValue)\(name)") }
    }

    // 计算属性
    var uppercaseName: String {
    get { return name.uppercased() }
    set { name = newValue }
    }
    }

    2. Getter 和 Setter 的生命周期

    (1) 计算属性(Computed Property)

    • Getter:每次访问属性时调用。
    • Setter:每次赋值时调用(必须有 set 才能修改值)。
      var person = Person(name: "Alice")
      print(person.uppercaseName) // 调用 getter
      person.uppercaseName = "Bob" // 调用 setter → 触发 name 的观察器

    (2) 存储属性(Stored Property)

    • 默认行为:直接读写存储的值。
    • 附加观察器:通过 willSetdidSet 监听变化。

    3. 观察器(willSetdidSet)的生命周期

    调用顺序

    当属性值被修改时,触发顺序如下:

    1. 原始值:保存当前值(用于 didSetoldValue)。
    2. willSet:新值即将写入(可访问 newValue)。
    3. 赋值操作:实际修改存储的值。
    4. didSet:新值已写入(可访问 oldValue)。

    示例流程

    var person = Person(name: "Alice")
    person.name = "Bob"

    // 输出:
    // willSet: Alice → Bob
    // didSet: Alice → Bob

    4. 关键区别与作用

    机制 触发时机 可访问的值 用途
    Getter 每次读取属性时 返回计算值 动态计算属性值(如格式化数据)。
    Setter 每次赋值时(计算属性) newValue 验证或处理新值(如过滤非法输入)。
    willSet 值被写入前 newValue 执行前置操作(如日志记录、触发 UI 更新)。
    didSet 值被写入后 oldValue 执行后置操作(如数据同步、发送通知)。

    5. 高级场景与注意事项

    (1) 初始化阶段不触发观察器

    • 观察器仅在初始化完成后生效
      init(name: String) {
      self.name = name // 不会触发 willSet/didSet
      }

    (2) 避免在 didSet 中重复触发修改

    • 死循环风险
      var score: Int = 0 {
      didSet {
      score = min(score, 100) // 会再次触发 didSet!
      }
      }
      解决方案:通过临时变量或条件判断避免循环。

    (3) 计算属性与观察器的互斥

    • 计算属性不能附加观察器(因为它的值由 getter/setter 动态决定)。

    (4) 性能影响

    • 观察器会增加调用开销:高频修改的属性需谨慎使用。

    6. 综合示例

    class Temperature {
    var celsius: Double = 0 {
    willSet {
    print("摄氏温度即将从 \(celsius) 变为 \(newValue)")
    }
    didSet {
    if celsius > 100 {
    print("警告:温度超过 100°C")
    }
    }
    }

    var fahrenheit: Double {
    get { return celsius * 1.8 + 32 }
    set { celsius = (newValue - 32) / 1.8 }
    }
    }

    let temp = Temperature()
    temp.fahrenheit = 212 // 触发 celsius 的观察器
    // 输出:
    // willSet: 0.0 → 100.0
    // 警告:温度超过 100°C

    总结

    • Getter/Setter:控制属性的读写行为(计算属性专属)。
    • willSet/didSet:监听存储属性的变化(初始化时不触发)。
    • 设计原则

      • 用计算属性封装派生数据。
      • 用观察器处理副作用(如持久化、UI 更新)。

      以下是一套详尽的 Swift 面试题与解析,涵盖你提到的关键点,包括结构体与类的差异、初始化、Codable 协议、Optional 本质、以及多线程编程(GCD 与 async/await)等内容。


    🧱 一、Struct 与 Class 的区别

    特性 Struct Class
    类型 值类型(Value Type) 引用类型(Reference Type)
    存储方式 每次赋值都会复制一份 多个引用指向同一实例
    继承 不支持继承 支持继承
    ARC 管理 不使用 ARC 使用 ARC
    可变性 let 定义不可变 let 定义的类实例,其属性可变
    可用于哪些场景 更适合轻量模型、不可变数据 更适合有生命周期管理、共享状态的对象

    结构体适用场景

    • 数据模型(如坐标、尺寸)
    • SwiftUI View
    • Codable 轻量数据解析

    🔧 二、Struct 与 Class 初始化注意事项

    Struct 初始化

    • 自动生成 memberwise initializer(逐一成员初始化器)
    • 如果你自定义了 init(),系统不再自动生成默认的成员初始化器
    struct Person {
    var name: String
    var age: Int
    }
    let p = Person(name: "Tom", age: 18)

    Class 初始化

    • 必须保证所有非可选属性在 init 中初始化
    • 可以定义 convenience 初始化器调用 designated 初始化器
    • 支持继承链中的初始化顺序
    class Animal {
    var name: String
    init(name: String) {
    self.name = name
    }
    }

    class Dog: Animal {
    var breed: String
    init(name: String, breed: String) {
    self.breed = breed
    super.init(name: name)
    }
    }

    🧬 三、Class 是否可以遵守 Codable 协议?

    ✅ 可以。

    class User: Codable {
    var name: String
    var age: Int
    init(name: String, age: Int) {
    self.name = name
    self.age = age
    }
    }

    注意:

    • 如果包含自定义 init 或继承结构体,需手动实现 encode(to:)init(from:)
    • 遇到嵌套 class 时,使用 JSONDecoder 会递归解码

    🧩 四、如何处理 Codable 字段名/类型不一致

    ✅ 方法一:使用 CodingKeys 自定义字段映射

    struct User: Codable {
    var name: String
    var age: Int

    enum CodingKeys: String, CodingKey {
    case name = "username"
    case age = "user_age"
    }
    }

    ✅ 方法二:字段类型不一致,手动 decode/encode

    struct User: Codable {
    var age: Int

    init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    let ageString = try container.decode(String.self, forKey: .age)
    self.age = Int(ageString) ?? 0
    }

    enum CodingKeys: String, CodingKey {
    case age
    }
    }

    ❓ 五、Optional 的本质是什么?

    enum Optional<Wrapped> {
    case none
    case some(Wrapped)
    }
    • Optional 是一个泛型 enum,有两个 case
    • nil 实际上就是 .none
    • 常用 if let / guard let / ?? 等语法糖简化解包过程

    🚦 六、Swift 多线程编程

    1. GCD(Grand Central Dispatch)

    异步队列 & 同步队列

    DispatchQueue.global().async {
    // 后台线程
    DispatchQueue.main.async {
    // 回主线程更新 UI
    }
    }

    延迟执行

    DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
    print("2 秒后执行")
    }

    并发队列 & 串行队列

    let serialQueue = DispatchQueue(label: "serial")
    let concurrentQueue = DispatchQueue(label: "concurrent", attributes: .concurrent)

    DispatchGroup

    let group = DispatchGroup()

    group.enter()
    fetchData1 { group.leave() }

    group.enter()
    fetchData2 { group.leave() }

    group.notify(queue: .main) {
    print("全部完成")
    }

    2. Swift 5.5+ async/await(推荐)

    func fetchData() async -> String {
    return "数据"
    }

    Task {
    let result = await fetchData()
    print(result)
    }

    并发执行任务

    async let a = loadA()
    async let b = loadB()
    let (resultA, resultB) = await (a, b)

    TaskGroup 使用

    await withTaskGroup(of: Int.self) { group in
    for i in 1...3 {
    group.addTask {
    return i * 2
    }
    }
    for await result in group {
    print(result)
    }
    }

    🧠 七、补充高级面试题建议

    ❓ Swift 中 enum 是值类型还是引用类型?

    • 值类型
    • 可以携带关联值
    • 可以实现协议、支持模式匹配(switch

    ❓ Swift 中 mutating 关键字作用?

    • 允许在 structenum 的方法中修改 self 或属性值

    ❓ Swift 如何防止 retain cycle?

    • 使用 weak / unowned 引用
    • 注意闭包捕获列表:[weak self] / [unowned self]

    以下是对 Swift 更高阶语法领域的详尽面试题扩展,涵盖 Protocol、泛型、闭包、高阶函数、Combine、RxSwift 及 ARC 内存管理。


    🧩 一、Protocol 协议相关面试题

    ❓ Protocol 和 Class/Struct 有什么不同?

    特性 Protocol Class/Struct
    目的 描述行为规范 数据结构定义
    是否可继承 支持多继承 Class 仅支持单继承
    是否可实例化 ❌ 不可 ✅ 可以
    可否添加默认实现 ✅ 通过 extension ✅ 直接实现

    ❓ 协议中的 associatedtype 有什么作用?

    • 定义占位符类型,用于泛型协议
    protocol DataSource {
    associatedtype T
    func item(at index: Int) -> T
    }
    • 不能直接在 let x: DataSource 中使用,需使用泛型约束 some DataSource

    ❓ Protocol Extension 有什么用?

    • 为协议统一添加默认实现
    • 允许扩展功能而不破坏已有 conformer 的代码
    extension CustomStringConvertible {
    var debugDescription: String {
    return description
    }
    }

    🧬 二、泛型(Generics)

    ❓ 如何写一个泛型函数?

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

    ❓ 泛型约束写法有哪些?

    func printDescription<T: CustomStringConvertible>(_ value: T) {
    print(value.description)
    }
    • 多协议约束:T: A & B
    • where 语句:where T.Element == String
    func allStrings<T: Sequence>(input: T) where T.Element == String {
    for str in input { print(str) }
    }

    🧠 三、闭包(Closure)

    ❓ 闭包与函数的区别?

    • 闭包是“可捕获上下文”的代码块
    • 函数是命名的、不能捕获上下文

    ❓ 闭包的语法简化过程?

    // 原始
    let add = { (a: Int, b: Int) -> Int in return a + b }

    // 省略类型
    let add = { a, b in a + b }

    // 尾随闭包
    someFunction {
    // do something
    }

    ❓ 如何避免闭包导致的循环引用?

    • 使用 [weak self][unowned self] 捕获列表
    loadData { [weak self] result in
    self?.updateUI()
    }

    📚 四、高阶函数面试题

    常见高阶函数总结

    函数 功能
    map 转换每个元素
    filter 过滤元素
    reduce 聚合为一个值
    compactMap 去除 nil 并转换
    flatMap 展平嵌套结构

    面试示例题

    let names = ["A", "B", "C"]
    let uppercased = names.map { $0.lowercased() }

    🔁 五、Combine 基础面试题

    ❓ Combine 的核心组件有哪些?

    组件 说明
    Publisher 发布者,发出数据流
    Subscriber 订阅者,接收数据流
    Subject 可作为 Publisher 和订阅点
    Operator 转换数据流,如 map, filter

    ❓ 示例:使用 Combine 实现双向绑定

    @Published var username: String = ""

    $username
    .sink { print("用户名:\($0)") }
    .store(in: &cancellables)

    🌊 六、RxSwift 基础面试题

    ❓ RxSwift 与 Combine 的异同?

    项目 RxSwift Combine
    苹果支持 ❌ 第三方 ✅ 官方
    平台 iOS 9+ iOS 13+
    错误处理 onError Failure 泛型
    资源管理 DisposeBag AnyCancellable

    ❓ 如何创建 Observable?

    Observable<String>.create { observer in
    observer.onNext("Hello")
    observer.onCompleted()
    return Disposables.create()
    }

    🗑️ 七、ARC 内存管理面试题

    ❓ Swift 的 ARC 如何工作?

    • 自动引用计数(ARC):每次引用计数 +1/-1
    • 当计数为 0 时释放内存

    ❓ strong / weak / unowned 区别?

    修饰符 特点
    strong 默认,增加引用计数
    weak 不增加计数,自动设为 nil
    unowned 不增加计数,不设为 nil(危险)

    ❓ 如何解决循环引用(Retain Cycle)?

    • 弱引用委托模式 delegate: SomeProtocol?
    • 闭包中使用 [weak self] 捕获

    🧪 Bonus:Swift 面试设计题

    1. 实现一个泛型缓存类
    2. 使用 RxSwift 实现登录输入校验
    3. Combine 版网络请求封装器
    4. 如何用闭包替代 delegate?
    5. 使用协议实现多种网络层解耦

    如果你希望我把这套完整面试题集整理成 Markdown、PDF、Xcode Playground、或面试笔记格式,我可以立即帮你生成。是否需要?或者还想深入 SwiftUI、内存布局、性能优化、源码解读等方向?

    iOS 面试题大全(Objective-C + Swift)


    一、语言基础

    Objective-C

    1. Objective-C 的类和对象结构?
    2. 什么是 Category 和 Extension?有什么区别?
    3. 什么是 Selector?怎么调用?
    4. id 和 instancetype 的区别?
    5. @property 的属性修饰符有哪些?
    6. 什么是 KVC 和 KVO?原理是什么?
    7. 什么是 Runtime?你用过哪些 Runtime 特性?
    8. 如何实现一个动态方法交换(Method Swizzling)?

    Swift

    1. struct 和 class 的区别?
    2. struct、class 初始化时属性/init 的注意事项?
    3. class 是否可以服从 Codable 协议?
    4. 如何利用 Codable 协议兼容接口字段名和类型?
    5. Optional 的本质是什么?
    6. Swift 是值语义还是引用语义?
    7. 什么是 mutating 关键字?
    8. enum 的高级用法有哪些?关联值、递归枚举?

    二、内存管理

    1. ARC 是什么?如何工作的?
    2. 强引用、弱引用、unowned 区别?
    3. 如何避免循环引用?delegate 用 weak?
    4. Block(ObjC)或 Closure(Swift)如何导致循环引用?
    5. @autoreleasepool 是做什么的?
    6. MRC 和 ARC 有哪些不同?是否可以混用?

    三、多线程与并发

    GCD

    1. GCD 的基本概念?同步/异步,串行/并行队列?
    2. 如何使用 DispatchGroup 实现任务组?
    3. dispatch_barrier 有什么作用?
    4. 如何使用信号量 DispatchSemaphore 控制线程?

    OperationQueue

    1. NSOperation 的优点是什么?如何自定义?
    2. 如何设置依赖?如何取消操作?

    Swift async/await

    1. Swift 中如何使用 async/await 实现并发任务?
    2. async let 和 TaskGroup 的区别与使用场景?
    3. actor 是什么?如何解决数据竞争?

    四、网络编程

    1. NSURLSession 常用方法?
    2. 如何处理 JSON?手动解析 vs Codable?
    3. 如何处理 HTTPS 双向验证?
    4. 如何实现断点续传?
    5. AFNetworking 和 Alamofire 的底层原理?

    五、数据库与持久化

    1. UserDefaults 用法和原理?
    2. plist 存储适合什么场景?
    3. Core Data 的基本使用?NSManagedObject?
    4. 如何设计 Core Data 的线程模型?
    5. FMDB 和 SQLite 如何使用?

    六、设计模式

    1. MVC、MVP、MVVM 有什么区别?
    2. 单例模式如何实现(ObjC 和 Swift)?
    3. 观察者模式在 iOS 中的实现?
    4. 代理模式如何实现?delegate vs closure?
    5. 响应链模式(Responder Chain)是什么?

    七、常用框架

    Combine

    1. Combine 的核心概念(Publisher/Subscriber/Operator)?
    2. @Published 和 ObservableObject 有什么区别?
    3. 如何取消订阅?AnyCancellable?

    RxSwift

    1. 什么是 Observable?Observer?
    2. 如何使用 Subjects?(Publish/Behavior/Replay/Async)
    3. DisposeBag 有什么用?
    4. RxSwift 与 Combine 有哪些异同?

    八、高阶 Swift 语法

    1. 泛型如何定义?如何约束?
    2. 如何实现一个泛型缓存类?
    3. Protocol 和 associatedtype 的高级用法?
    4. Swift 的闭包语法和使用?
    5. 什么是逃逸闭包(@escaping)?
    6. 高阶函数:map/filter/reduce/flatMap/compactMap 的用法?
    7. 如何使用 Swift 的 Result 类型处理异步任务?

    九、其他基础知识

    1. App 的启动过程是什么?
    2. iOS 的事件传递机制?(Hit-Testing)
    3. UIResponder 的作用?
    4. 通知中心 NotificationCenter 原理?
    5. iOS 的沙盒机制与目录结构?
    6. App 生命周期与场景管理(SceneDelegate)?

    欢迎根据职位要求重点准备某些模块,是否还需要我整理为 PDF 或可搜索的 Markdown 文件?
    以下是对文档内容的进一步完善建议,包括新增几个关键面试模块与问题点,特别是:

    • Swift 的属性包装器(Property Wrappers)
    • Swift 的访问控制与模块化
    • iOS 性能优化与调试工具
    • 测试与 CI/CD 流程
    • iOS 安全机制

    你可以选择我来更新文档,也可以先看看新增内容如下:


    十、Swift 进阶机制

    1. Property Wrapper 的原理和常见用法(@State、@Published、@UserDefault 等)?
    2. Swift 的访问控制(open、public、internal、fileprivate、private)有哪些场景?
    3. Swift 的模块化开发方式?如何拆分模块?
    4. 如何实现依赖注入(DI)?有无使用框架(如 Resolver、Swinject)?

    十一、性能优化与调试

    1. Instruments 中常用工具有哪些?Time Profiler、Allocations、Leaks 的使用?
    2. 如何查找内存泄漏和性能瓶颈?
    3. View 的离屏渲染(Offscreen Rendering)问题及优化?
    4. 如何优化列表滚动性能(特别是 SwiftUI)?

    十二、测试与 CI/CD

    1. 单元测试、UI 测试的区别和框架(XCTest/XCUITest)?
    2. 如何进行 Mock 测试?
    3. 使用 Xcode Server、Jenkins、GitHub Actions 做 CI/CD?
    4. Fastlane 的基本使用方法?

    十三、iOS 安全性

    1. iOS 应用如何做本地数据加密(Keychain 使用)?
    2. 什么是代码混淆与反调试手段?
    3. iOS 的 App Transport Security(ATS)是什么?
    4. 如何处理用户隐私合规问题(IDFA、App Tracking Transparency)?

    如你希望我将这些内容补充进当前 Canvas 文档,请回复“请更新文档”;或者如希望将其导出为 PDF 或 Markdown 文件,我也可直接生成。是否需要我继续整理更高阶的系统设计题?
    在 Swift 中,property gettersetter 是属性访问的核心机制,允许你自定义属性的读取和写入行为。而 willSetdidSet 是 Swift 中存储属性的观察者(Property Observers),用于在属性即将被设置前或刚被设置后响应操作。下面详细介绍这两类机制及它们的生命周期、作用与区别。


    一、Getter 与 Setter(计算属性)

    **计算属性(Computed Property)**使用 getset 明确地声明读取和写入逻辑。

    struct Rectangle {
    var width: Double
    var height: Double

    var area: Double {
    get {
    return width * height
    }
    set {
    // 可根据需要更新 width 或 height
    width = sqrt(newValue)
    height = sqrt(newValue)
    }
    }
    }

    生命周期:

    • get 在每次读取属性时调用。
    • set 在每次设置属性值时调用。
    • set 可省略参数名,使用系统默认的 newValue
    • 计算属性 不能使用 willSet/didSet(因为它们没有存储值)。

    二、willSet 与 didSet(存储属性观察者)

    观察者用于监听存储属性的变化,常用于副作用操作(如 UI 更新、日志记录)。

    class Person {
    var name: String = "Tom" {
    willSet {
    print("即将设置 name 为 \(newValue)")
    }
    didSet {
    print("name 已从 \(oldValue) 改为 \(name)")
    }
    }
    }

    生命周期和执行顺序:

    (设置属性值发生时)
    1. willSet(newValue) 执行 —— 传入新的值
    2. 实际赋值 name = newValue
    3. didSet(oldValue) 执行 —— 传入旧的值

    特点和规则:

    特性 willSet didSet
    触发时机 设置前 设置后
    是否可访问新旧值 newValue(默认名) oldValue(默认名)
    可否更改新值 ❌(只读) ✅(但再次触发 willSet)
    对比 get/set 是副作用处理 非属性逻辑/行为型处理
    对比 get/set 应用场景 响应式(通知/记录/限制等) 不是值计算

    三、get/set 与 willSet/didSet 的本质区别

    项目 get / set(计算属性) willSet / didSet(观察者)
    是否存在存储值 ❌ 不存储数据,只计算 ✅ 是真实的存储属性
    可否添加计算逻辑 ✅(如 area 计算) ✅(响应变化,如 UI 刷新)
    支持作用范围 struct、class、enum 中所有属性 仅限 存储属性(不适用于计算属性)
    使用场景 自定义属性值逻辑,如转换、代理其他属性 监听属性值变化,例如通知、同步更新

    四、实践建议

    • 如果你想自定义 属性值的逻辑(如格式转换),使用 get/set
    • 如果你想在 属性变化时响应操作(如 UI 通知或日志记录),使用 willSet/didSet
    • 避免在 didSet 中再次改变该属性值,容易引发递归循环。
    • 只在确实需要响应属性变化时使用观察者,否则可能影响性能或可读性。

    在 Swift 中,属性的 gettersetter 及其观察器(willSetdidSet)的生命周期和调用顺序是属性管理的核心机制。以下是它们的详细解析:


    1. 基本结构

    Swift 中的属性可以分为:

    • 存储属性(Stored Property):直接存储值,可附加观察器。
    • 计算属性(Computed Property):通过 getter/setter 动态计算值,不可附加观察器。

    示例代码

    struct Person {
    // 存储属性 + 观察器
    var name: String {
    willSet { print("willSet: \(name)\(newValue)") }
    didSet { print("didSet: \(oldValue)\(name)") }
    }

    // 计算属性
    var uppercaseName: String {
    get { return name.uppercased() }
    set { name = newValue }
    }
    }

    2. Getter 和 Setter 的生命周期

    (1) 计算属性(Computed Property)

    • Getter:每次访问属性时调用。
    • Setter:每次赋值时调用(必须有 set 才能修改值)。
      var person = Person(name: "Alice")
      print(person.uppercaseName) // 调用 getter
      person.uppercaseName = "Bob" // 调用 setter → 触发 name 的观察器

    (2) 存储属性(Stored Property)

    • 默认行为:直接读写存储的值。
    • 附加观察器:通过 willSetdidSet 监听变化。

    3. 观察器(willSetdidSet)的生命周期

    调用顺序

    当属性值被修改时,触发顺序如下:

    1. 原始值:保存当前值(用于 didSetoldValue)。
    2. willSet:新值即将写入(可访问 newValue)。
    3. 赋值操作:实际修改存储的值。
    4. didSet:新值已写入(可访问 oldValue)。

    示例流程

    var person = Person(name: "Alice")
    person.name = "Bob"

    // 输出:
    // willSet: Alice → Bob
    // didSet: Alice → Bob

    4. 关键区别与作用

    机制 触发时机 可访问的值 用途
    Getter 每次读取属性时 返回计算值 动态计算属性值(如格式化数据)。
    Setter 每次赋值时(计算属性) newValue 验证或处理新值(如过滤非法输入)。
    willSet 值被写入前 newValue 执行前置操作(如日志记录、触发 UI 更新)。
    didSet 值被写入后 oldValue 执行后置操作(如数据同步、发送通知)。

    5. 高级场景与注意事项

    (1) 初始化阶段不触发观察器

    • 观察器仅在初始化完成后生效
      init(name: String) {
      self.name = name // 不会触发 willSet/didSet
      }

    (2) 避免在 didSet 中重复触发修改

    • 死循环风险
      var score: Int = 0 {
      didSet {
      score = min(score, 100) // 会再次触发 didSet!
      }
      }
      解决方案:通过临时变量或条件判断避免循环。

    (3) 计算属性与观察器的互斥

    • 计算属性不能附加观察器(因为它的值由 getter/setter 动态决定)。

    (4) 性能影响

    • 观察器会增加调用开销:高频修改的属性需谨慎使用。

    6. 综合示例

    class Temperature {
    var celsius: Double = 0 {
    willSet {
    print("摄氏温度即将从 \(celsius) 变为 \(newValue)")
    }
    didSet {
    if celsius > 100 {
    print("警告:温度超过 100°C")
    }
    }
    }

    var fahrenheit: Double {
    get { return celsius * 1.8 + 32 }
    set { celsius = (newValue - 32) / 1.8 }
    }
    }

    let temp = Temperature()
    temp.fahrenheit = 212 // 触发 celsius 的观察器
    // 输出:
    // willSet: 0.0 → 100.0
    // 警告:温度超过 100°C

    总结

    • Getter/Setter:控制属性的读写行为(计算属性专属)。
    • willSet/didSet:监听存储属性的变化(初始化时不触发)。
    • 设计原则
      • 用计算属性封装派生数据。
      • 用观察器处理副作用(如持久化、UI 更新)。
      • 避免在观察器中修改自身属性导致循环。
    支持一下
    扫一扫,支持forsigner
    • 微信扫一扫
    • 支付宝扫一扫