MST

星途 面试题库

面试题:Swift 通知中心优化之性能问题

在使用 Swift 通知中心时,频繁的添加和移除观察者可能会带来性能问题。请分析可能出现性能问题的场景,并提出至少两种优化方案,用代码示例说明其中一种方案。
46.6万 热度难度
编程语言Swift

知识考点

AI 面试

面试题答案

一键面试

可能出现性能问题的场景

  1. 大量观察者频繁添加移除:如果在一个循环中或者高频率的事件处理中,不断地添加和移除观察者,会导致系统频繁分配和释放内存,增加内存管理的开销。例如在一个 UITableViewcellForRowAt 方法中,每次创建 cell 时添加观察者,cell 被重用时移除观察者,随着 tableView 的滚动,这种操作会非常频繁。
  2. 通知中心内部维护开销:通知中心需要维护观察者的列表,频繁的添加和移除操作会使通知中心花费更多时间来更新这个列表,尤其是在观察者数量较多时,每次更新列表的时间复杂度会增加。

优化方案

  1. 合并操作:尽量减少添加和移除观察者的频率。可以在合适的生命周期方法中进行添加和移除,例如在视图控制器的 viewDidLoad 中添加观察者,在 viewWillDisappeardeinit 中移除观察者,而不是在频繁调用的方法中操作。
  2. 使用弱引用:通过使用弱引用的方式来添加观察者,这样可以避免因循环引用导致的内存泄漏问题,并且在对象被释放时,通知中心会自动移除对应的观察者,减少手动移除的操作。

代码示例(使用弱引用优化方案)

import UIKit

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        NotificationCenter.default.addObserver(self, selector: #selector(handleNotification(_:)), name: UIApplication.didEnterBackgroundNotification, object: nil)
    }

    @objc func handleNotification(_ notification: Notification) {
        print("Received didEnterBackgroundNotification")
    }

    deinit {
        NotificationCenter.default.removeObserver(self, name: UIApplication.didEnterBackgroundNotification, object: nil)
    }
}

在上述代码中,在 viewDidLoad 方法里添加了一个通知观察者,在 deinit 方法里移除观察者。如果不想手动在 deinit 里移除,可以使用弱引用的方式添加观察者:

import UIKit

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        let weakSelf = WeakRef(self)
        NotificationCenter.default.addObserver(forName: UIApplication.didEnterBackgroundNotification, object: nil, queue: nil) { notification in
            weakSelf.value?.handleNotification(notification)
        }
    }

    func handleNotification(_ notification: Notification) {
        print("Received didEnterBackgroundNotification")
    }
}

class WeakRef<T: AnyObject> {
    weak var value: T?
    init(_ value: T) {
        self.value = value
    }
}

这样在 ViewController 对象被释放时,通知中心会自动处理相关的观察者移除,无需手动调用 removeObserver