未使用的不可变接收器的编译器警告,但使用_会导致测试失败

时间:2020-05-10 20:31:25

标签: swift swift5 combine

我有一个测试,可以验证在有新设备可用时是否正在发布消息:

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()
}

然后我的测试超时,随后失败。有没有更好的方法来声明我的接收器?有什么方法可以告诉编译器错误吗?是否应该将其归档为错误?我理解为什么编译器会认为该变量未使用,但是在这种情况下,似乎应该有一种方法来禁用警告,或者更可能的是,我正在做未按预期的事情。

2 个答案:

答案 0 :(得分:0)

编译器提示您的是,接收器需要存储。平常的事就是写

deviceConnectedPublisher.sink { _ in
    expectation.fulfill()
}.store(in: &self.storage)

......,其中storageSet<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.