【发布时间】:2020-06-09 08:43:02
【问题描述】:
我必须在我的应用程序中使用第 3 方 SDK,所以我认为这是在现实生活中使用 Combine 并将这个 SDK 包装在一个薄薄的 Combine 助手层中的绝佳机会。我能够相当容易地涵盖所有内容,但现在我面临的问题是我的某些send 方法从未交付。我将分享我的一些代码,以便更好地了解我所拥有的。
final class Manager: NSObject {
private let sdkManager: BleManager
// Private Publishers
private let newDeviceFoundPublisher = PassthroughSubject<Device, Error>()
private let connectedToDevicePublisher = PassthroughSubject<Device, Error>()
private let deviceDataPublisher = PassthroughSubject<DeviceData, Never>()
init(manager: BleManager = BleManager.shareInstance()) {
self.vvBleManager = manager
super.init()
self.sdkManager.delegate = self
}
func startScanning(deviceType: DeviceType) -> AnyPublisher<Device, Error> {
sdkManager.startScan(deviceType)
return newDeviceFoundPublisher
.map { Device.init }
.timeout(.seconds(10), scheduler: DispatchQueue.main, customError: { .scanningTimeout })
.eraseToAnyPublisher()
}
func stopScanning() {
sdkManager.stopScan()
}
func connect(to device: Device) -> AnyPublisher<Device, Error> {
sdkManager.connect(device)
return connectedToDevicePublisher.eraseToAnyPublisher()
}
func disconnect(device: DeviceType) {
sdkManager.disconnect(device)
}
func deviceData() -> AnyPublisher<DeviceData, Never> {
return deviceDataPublisher.eraseToAnyPublisher()
}
}
extension VivalnkManager: BLEDelegate {
func onDeviceFound(_ device: Device!) {
newDeviceFoundPublisher.send(device)
}
func onConnected(_ device: Device!) {
connectedToDevicePublisher.send(device)
connectedToDevicePublisher.send(completion: .finished)
}
func onReceiveData(_ data: Any!) {
if let newData = try? DeviceData(from: data!) {
deviceDataPublisher.send(newData)
}
}
}
这里没有发生什么疯狂的事情,当我从 SDK 检查日志时,所有方法都在正确执行,并且代理正在被新数据等触发。这就是我知道我的代码一定有问题的方式。现在,我正在尝试实现但无法使其工作的是以下代码示例:
manager
.startScanning(deviceType: .swiftometr)
.filter { $0.deviceId == id }
.handleEvents(receiveOutput: { _ in environment.manager.stopScanning() })
.flatMap { environment.manager.connect(to: $0) }
.sink(receiveCompletion: { _ in print("Completion") },
receiveValue: { _ in print("Value") })
.store(in: &cancellables)
因此,在我的控制台中打印了一段时间后,我只能看到Completion,但我怀疑这是来自timeout,我在scanning 方法中。我尝试了许多不同的方法,但没有任何效果。然后,我想,也许flatMap 不是这样工作的,所以我尝试将几个URLSession.shared.dataTaskPublishers 嵌套在一起,它们工作得很好!
更多的挖掘,我处于我理解为什么这一切发生的状态。看起来sdkManager.connect(device) 发生得如此之快,以至于我的应用程序无法订阅,所以这就是我永远不会收到任何价值的原因。对我有帮助的只是将其包装在这样的延迟块中:
func connect(to device: Device) -> AnyPublisher<Device, Error> {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
sdkManager.connect(device)
}
return connectedToDevicePublisher.eraseToAnyPublisher()
}
现在connect 能够返回AnyPublisher 并允许订阅者在send 发生之前订阅。尽管它有效,但感觉就像是一种 hacky 的做事方式,我对此并不满意。寻找更好的方法。
【问题讨论】: