将数组从管理器 class 发布到 ViewModel,然后再到 View

Publishing array from a manager class to ViewModel and then to View

我正在尝试建立一个 MVVM 模式以从 BLEManager 获取值到 ViewModel,然后再到我的视图。但不知何故,我无法将 BLEManager class 中的值发送到 View Model。以下是我的数据流:

View(包含一些内容的主视图)<- View(一个包含列表的内容)<- ViewModel(将数据作为数组提供给视图中列表的视图模型)<- BleManager(ble 扫描仪到获取可用的蓝牙设备)

BleManager:

    class BLEManager: NSObject, ObservableObject {
    var centralManager: CBCentralManager!
    @Published var peripherals = [CBPeripheral]()
    @Published var isSwitchedOn = false
    
    override init() {
        super.init()
        centralManager = CBCentralManager(delegate: self, queue: nil)
    }
    
    func startScanning() {
        centralManager.scanForPeripherals(withServices: nil, options: nil)
    }
    
    func stopScanning() {
        centralManager.stopScan()
    }
}

extension BLEManager: CBCentralManagerDelegate, CBPeripheralDelegate {
    func centralManagerDidUpdateState(_ central: CBCentralManager) {
        if central.state == .poweredOn {
            isSwitchedOn = true
        }
        else {
            isSwitchedOn = false
        }
    }
    
    func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
        guard let peripheralName = advertisementData[CBAdvertisementDataLocalNameKey] as? String else {
            return
        }
        if !peripherals.contains(where: { [=11=].name == peripheralName }), let name = peripheral.name {
            peripherals.append(peripheral)
        }
    }
    
    func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
        peripheral.delegate = self
        peripheral.discoverServices(nil)
    }
    
    func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
        print("didFailToConnect")
    }
    
    func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
        print("didDisconnectPeripheral")
    }
}

我不知道如何为我的视图模型编写代码,以下是它的当前状态: 视图模型:

    class NearbyBLEListViewModel: ObservableObject {
    @Published var authenticationResult: Bool?
    @Published var bleDevices = [BLEInfo]()
    @Published var blutoothOff: Bool?
    
    var bleManager = BLEManager()
    
    
    func startScanning() {
        bleManager.startScanning()
        bleDevices = bleManager.peripherals.map { BLEInfo(bleId: [=12=].name ?? "NA", hash: "") }
//        if bleManager.isSwitchedOn {
//            blutoothOff = false
//            bleDevices = bleManager.peripherals.map { bleInfo(bleId: [=12=].name ?? "NA", hash: "") }
//            print(bleDevices)
//        } else {
//            blutoothOff = true
//        }
    }
    
    func getBLEDevices() {
        bleDevices = bleManager.peripherals.map { BLEInfo(bleId: [=12=].name ?? "NA", hash: "") }
        print(bleDevices)
    }
}

在视图中使用如下:

    struct NearbyBLEListView: View {
    @ObservedObject var bleManager = BLEManager()
    @StateObject private var viewModel = NearbyBLEListViewModel()
    
    var body: some View {
        VStack {
            Text("BLEs nearby:")
                .font(.system(size: 22, weight: .bold, design: .default))
                .padding()
                .foregroundColor(.black)           
            List(viewModel.bleDevices) { ble in
                HStack {
                    Text(ble.bleId)
                }
                    }
                    .navigationTitle("News")
                    .onAppear(perform: viewModel.startScanning)
            
        }
    }
}

最后是我的最高观点:

var body: some View {
    NavigationView {
        VStack(alignment: .center) {
            buttonView
            NearbyBLEListView()
        }
        .navigationTitle("")
        .toolbar {
            moreButtonView
        }
    }
}

我刚刚开始使用 SwiftUI,所以我可能不了解 SwiftUI 的最佳实践。有人可以帮我吗?

摆脱视图模型对象,我们不在 SwiftUI 中使用 MVVM。 View 数据结构已经是屏幕上实际视图的模型,例如SwiftUI 为我们更新的 UILabels、UITables 等。我们可以将相关的变量和逻辑移动到自定义 @State 结构中,以使代码更易于测试,但是在您的情况下它看起来像这样:

struct NearbyBLEListView: View {
    @StateObject var bleManager = BLEManager()

    var body: some View {
        VStack {
            Text("BLEs nearby:")
            .font(.system(size: 22, weight: .bold, design: .default))
            .padding()
            .foregroundColor(.black)           
            List(bleManager.bleDevices) { ble in
                HStack {
                    Text(ble.bleId)
                }
            }
            .navigationTitle("News")
        }
    }
}
当视图出现时,

@StateObjects 是初始化的,因此您可以在 BLEManager 的 init 中开始扫描。您还需要 BLEManager 来保存您的 BLEDevice 结构数组,例如

class BLEManager: NSObject, ObservableObject {
    @Published var bleDevices = [BleDevice]()