首页 > 解决方案 > 如何存储在委托类中接收的值,在外部类中?

问题描述

有一个 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 逻辑,并且数据与其他用户数据一起存储。斯威夫特有可能吗?

Ps 我对 Swift 很陌生。有 JS 经验。

已编辑

在当前情况下,BLEmanager 从一个特定的外设接收数据。数据代表一个人的体重,要清楚。除此之外,还有一个包含人类生物特征数据(年龄、身高、性别)的结构。归根结底,生物特征数据 + 来自设备的数据(体重)密切相关,并用于相同的计算。

结果

我能够实施 Cristik 的方法。正如他所描述的,在我的情况下,唯一的区别是订阅发生在视图的.onAppear()修饰符中,而不是在类初始化中。将出版商传给班级时遇到了麻烦。

标签: swiftcore-bluetoothcbcentralmanager

解决方案


我想以这种方式移动这些数据,因此当前类(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 数据感兴趣的人都只需订阅该发布者即可。

现在,在接收端,假设您还需要ObservableObjectSwiftUI 视图,您可以编写以下内容:

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 数据的方法。这也有助于分离应用程序其余部分的关注点。


推荐阅读