百度深圳iOS二面真题解析:技术深度与工程实践的双重考察

一、内存管理与性能优化:从基础到进阶

1.1 循环引用的检测与解决
面试中常考察开发者对循环引用场景的识别能力。例如,在闭包中持有self时若未使用weak修饰,会导致对象无法释放。
示例代码

  1. class ViewController: UIViewController {
  2. private var completion: (() -> Void)?
  3. override func viewDidLoad() {
  4. super.viewDidLoad()
  5. completion = { [weak self] in // 使用weak避免循环引用
  6. self?.view.backgroundColor = .red
  7. }
  8. }
  9. }

关键点:需明确weakunowned的区别,前者在对象释放时自动置为nil,后者会引发运行时错误。

1.2 内存泄漏的排查工具
百度面试官可能要求描述使用Instruments中的LeaksAllocations工具定位泄漏的步骤。例如:

  • Leaks工具中观察内存增长曲线;
  • 通过Allocations的堆栈信息定位具体代码位置。
    最佳实践:定期在开发阶段运行内存分析,而非仅在测试阶段。

二、多线程与并发编程:核心机制与风险控制

2.1 GCD的死锁场景分析
典型问题:在主队列中同步执行任务会导致死锁。
错误示例

  1. DispatchQueue.main.sync {
  2. print("This will cause deadlock")
  3. }

解决方案

  • 异步派发任务:DispatchQueue.main.async { ... }
  • 使用DispatchWorkItem实现可取消的任务。

2.2 线程安全的数据结构
面试中可能要求实现一个线程安全的队列。常见方案包括:

  • 使用NSLock@synchronized(Objective-C);
  • Swift中推荐os_unfair_lockDispatchQueue的屏障机制。
    示例代码

    1. class ThreadSafeQueue<T> {
    2. private var queue = [T]()
    3. private let lock = NSLock()
    4. func enqueue(_ element: T) {
    5. lock.lock()
    6. queue.append(element)
    7. lock.unlock()
    8. }
    9. func dequeue() -> T? {
    10. lock.lock()
    11. defer { lock.unlock() }
    12. return queue.isEmpty ? nil : queue.removeFirst()
    13. }
    14. }

三、架构设计:模块化与可维护性

3.1 MVC与MVVM的对比
面试官可能要求分析两种架构的适用场景:

  • MVC:适合简单界面,但易导致ViewController臃肿;
  • MVVM:通过ViewModel解耦业务逻辑,适合复杂交互场景。
    代码示例(MVVM绑定)
    ```swift
    class ViewModel {
    @Published var title: String = “”

    func fetchData() {

    1. // 模拟网络请求
    2. DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
    3. self.title = "Data Loaded"
    4. }

    }
    }

class ViewController: UIViewController {
private let viewModel = ViewModel()
private var cancellables = Set()

  1. override func viewDidLoad() {
  2. super.viewDidLoad()
  3. viewModel.$title
  4. .receive(on: DispatchQueue.main)
  5. .sink { [weak self] title in
  6. self?.title = title
  7. }
  8. .store(in: &cancellables)
  9. viewModel.fetchData()
  10. }

}

  1. **3.2 组件化与路由设计**
  2. 百度面试可能涉及模块间通信的方案,例如:
  3. - 使用`Protocol-Oriented`设计解耦模块;
  4. - 通过`URL Scheme``Coordinator`模式管理页面跳转。
  5. **关键原则**:避免直接依赖具体类,优先通过接口抽象。
  6. ### 四、性能优化:从代码到系统级
  7. **4.1 列表滚动卡顿优化**
  8. 常见问题包括:
  9. - 单元格高度计算未复用;
  10. - 图片加载未异步处理。
  11. **解决方案**:
  12. - 使用`UITableView.automaticDimension`并预估高度;
  13. - 图片加载库(如`Kingfisher`)的异步解码功能。
  14. **代码示例**:
  15. ```swift
  16. func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
  17. let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
  18. let url = URL(string: "https://example.com/image.jpg")
  19. cell.imageView?.kf.setImage(with: url) // 假设使用Kingfisher
  20. return cell
  21. }

4.2 离线缓存策略
面试中可能要求设计一个数据缓存系统,需考虑:

  • 缓存过期时间(如TTL);
  • 磁盘与内存的分级存储。
    实现思路
    ```swift
    protocol Cacheable {
    func setObject(_ object: Any, forKey key: String, ttl: TimeInterval?)
    func object(forKey key: String) -> Any?
    }

class HybridCache: Cacheable {
private let memoryCache = NSCache()
private let diskCachePath = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)[0]

  1. func setObject(_ object: Any, forKey key: String, ttl: TimeInterval? = nil) {
  2. // 内存缓存
  3. memoryCache.setObject(object, forKey: key as NSString)
  4. // 磁盘缓存(简化版)
  5. if let data = try? JSONSerialization.data(withJSONObject: object, options: []) {
  6. let fileURL = diskCachePath.appendingPathComponent(key)
  7. try? data.write(to: fileURL)
  8. }
  9. }

}
```

五、系统原理与底层机制

5.1 RunLoop与事件循环
面试官可能询问RunLoop的作用及模式(如NSDefaultRunLoopModeUITrackingRunLoopMode的区别)。
关键点

  • RunLoop是线程的事件处理核心;
  • 滚动时切换模式可避免卡顿。

5.2 图像渲染流程
需掌握从CALayerCore Animation的渲染管线,例如:

  • 离屏渲染的触发条件(如cornerRadius + masksToBounds);
  • 通过shouldRasterize优化复杂图层。

六、备考建议与面试技巧

  1. 代码实战:在LeetCode或本地项目中实现典型问题(如二叉树遍历、链表反转);
  2. 源码阅读:分析SwiftNIOAlamofire等开源库的设计;
  3. 模拟面试:与同行进行技术对练,重点训练代码的鲁棒性(如异常处理)。

总结:百度深圳的iOS二面注重技术深度与工程能力的结合,求职者需在掌握基础API的同时,深入理解系统原理与架构设计。通过系统性准备与实战演练,可显著提升通过率。