我有一个测试,可以验证在有新设备可用时是否正在发布消息:
let deviceConnectedPublisher = NotificationCenter.default.publisher(for: .deviceAdded)
.compactMap { $0.object as AnyObject as? ConnectableDevice }
let sink = deviceConnectedPublisher.sink { _ in
expectation.fulfill()
}
这很好用,但是我有一个编译器警告:
从未使用过对不可变值“接收器”的初始化;考虑将其替换为“ _”或将其删除
但是,如果我接受编译器的建议并将其更改为
let _ = deviceConnectedPublisher.sink { _ in
expectation.fulfill()
}
然后我的测试超时,随后失败。有没有更好的方法来声明我的接收器?有什么方法可以告诉编译器错误吗?是否应该将其归档为错误?我理解为什么编译器会认为该变量未使用,但是在这种情况下,似乎应该有一种方法来禁用警告,或者更可能的是,我正在做未按预期的事情。
答案 0 :(得分:0)
编译器提示您的是,接收器需要存储。平常的事就是写
deviceConnectedPublisher.sink { _ in
expectation.fulfill()
}.store(in: &self.storage)
......,其中storage
是Set<AnyCancellable>
或[AnyCancellable]
实例属性。这样可以使管道保持活动状态,并使其生命周期自动绑定到周围的对象(例如视图控制器)。
答案 1 :(得分:0)
在将AnyCancellable
存储在名为sink
的本地属性中的代码中,编译器会发出警告,警告您切勿使用该变量。这意味着允许编译器优化变量并立即销毁AnyCancellable
。
但是,您可能正在Debug构建配置中运行测试。调试配置的默认设置禁用优化。因此,编译器不会不优化sink
变量,而只会在作用域末尾销毁它。假设到那时,您已经发布了所需的通知。
在使用_
的代码中,编译器立即销毁返回的AnyCancellable
。这会取消您对通知发布者的订阅,因此通知永远不会传递到您的sink
闭包中。
您可以使用withExtendedLifetime
函数来静默该警告,并确保稍后不会破坏该本地属性的值:
let sink = deviceConnectedPublisher.sink { _ in
expectation.fulfill()
}
// post notification here
withExtendedLifetime(sink) { }
// Only now can sink be destroyed.