假设我有这个代码:
class Foo {
private let nc: NotificationCenter
init(nc: NotificationCenter = .default) {
self.nc = nc
nc.addObserver(forName: Notification.Name.Foo, object: nil, queue: .main) { _ in
Task { [weak self] in
self?.doSomething()
}
}
}
deinit {
nc.removeObserver(self, name: Notification.Name.Foo, object: nil)
}
@objc
private func doSomething() async {
// triggers some async code
}
}
字符串
我想写一个单元测试来确保这个观察者在类被释放时被移除。
Apple文档规定:
如果使用addObserver(forName:object:queue:using:)创建观察者,则应在系统释放addObserver(forName:object:queue:using:)指定的任何对象之前调用此方法或removeObserver(_:name:object:)。
我嘲笑了一个通知中心:
class MockNotificationCenter: NotificationCenter {
var notifications: [NSNotification.Name?] = []
override func addObserver(
forName name: NSNotification.Name?,
object obj: Any?,
queue: OperationQueue?,
using block: @escaping (Notification) -> Void) -> NSObjectProtocol
{
notifications.append(name)
return super.addObserver(forName: name, object: obj, queue: queue, using: block)
}
override func removeObserver(
_ observer: Any,
name aName: NSNotification.Name?,
object anObject: Any?
) {
notifications = notifications.filter { $0 != aName }
super.removeObserver(observer, name: aName, object: anObject)
}
型
下面是我的单元测试:
func testDeinit_DoesRemoveObserver() {
// Given
var sut: Foo?
let mockNC = MockNotificationCenter()
// When
sut = Foo(notificationCenter: mockNC)
// Then
XCTAssertEqual(mockNC.notifications.count, 1) // Succeeds
// When
sut = nil
// Then
XCTAssertEqual(mockNC.notifications.count, 0) // Fails
}
型
XCTAssertEqual失败:(“1”)不等于(“0”)
我如何修复这个问题,以Assert在解除分配我的观察对象时,观察者已从通知中心删除?
1条答案
按热度按时间4ktjp1zp1#
问题是在你的
Foo
类中有一个保留周期。在addObserver
闭包中,你正在捕获Foo类示例本身。它应该是:字符串
当
sut
被赋值为nil时,deinit
和removeObserver
都没有被调用,通知数组仍然是一个元素。