如何存储在委托类中接收的值,在外部类中?

2022-09-05 00:00:00 swift core-bluetooth cbcentralmanager
有一个BLEManager类,负责扫描、连接和接收来自蓝牙低能耗(BLE)设备的数据。看起来是这样的:

class BLEManager: ObservableObject, OtherProtocols {
    private var myCentral: CBCentralManager!
    @Published var data = 0.0

    override init() {
        super.init()

        myCentral = CBCentralManager(delegate: self, queue: nil)
        myCentral.delegate = self
    }

    // ...some functions that scan, establish connection, etc.

    func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
        // here I receive raw value, handle it and get a data to work with
        
        data = 10.0 // imagine it's the data received from BLE device 
    } 
}

现在,要使用的数据存储在这个类中。我想以这种方式移动这些数据,因此当前类(BLEManager)只负责BLE逻辑,数据与其他用户数据一起存储。 在SWIFT中可能吗?

附注:我是斯威夫特的新手。有JS经验。

编辑

在当前情况下,BLEManager从一个特定的外围设备接收数据。明确地说,这些数据代表了人类的体重。除此之外,还有一个包含人类生物特征数据(年龄、身高、性别)的结构。归根结底,生物特征数据+来自设备(体重)的数据密切相关,并在相同的计算中使用。

结果

我能够实现Cristik的方法。唯一的区别是,在我的例子中,替换发生在View的.onAppear()修饰符中,而不是像他描述的那样发生在类init上。将发布者传递给类时遇到问题。


解决方案

我想以这种方式移动这些数据,这样当前类(BLEManager)只负责BLE逻辑,数据与其他用户数据一起存储

这是一个很好的心态,因为目前你的BLEManager打破了单一责任原则,即有多个责任。ObservedObject部分是SwiftUI特定的部分,因此从类中提取是有意义的。

现在,在实现方面,您可以执行的第一步是将data属性转换为发布者。这将允许客户端连接到数据流,并允许您在应用的其余部分中循环发布者,而不是BLEManager类。

import Combine

class BLEManager: OtherProtocols {
    // you can use `Error` instead of `Never` if you also want to
    // report errors which make the stream come to an end
    var dataPublisher: AnyPublisher<Int, Never> { _dataPublisher.eraseToAnyPublisher() }

    private var myCentral: CBCentralManager!

    // hiding/encapsulating the true nature of the publisher
    private var _dataPublisher = PassthroughSubject<Int, Never>()

    // ...

    func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
        _dataPublisher.send(10.0) // imagine it's the data received from BLE device 
    } 

这样,任何有兴趣接收BLE数据的人都可以直接订阅该发布者。

现在,在接收端,假设您的SwiftUI视图也需要ObservableObject,您可以编写以下内容:

class ViewModel: ObservableObject {
    @Published var data: Int = 0
    
    init(dataPublisher: AnyPublisher<Int, Never>) {
        // automatically updates `data` when new values arrive
        dataPublisher.assign(to: &$data)
    }
}

如果您不使用SwiftUI(由于ObservableObject一致性,我假设您使用),则您可以sink到同一发布者以接收数据。


SwiftUI或UIKit,一旦您在某个地方实例化了BLEManager,您可以对应用程序的其余部分隐藏它,并通过传播发布者来提供订阅BLE数据的方法。这也有助于分离应用程序其余部分的关注点。

相关文章