选择器选项无法动态更新SwiftUI

时间:2020-07-16 11:56:34

标签: ios swift swiftui picker

我有一个选择器,当它发现新的BLE外设时需要动态更新。但是,选择器永远不会使用新值进行更新。

我有一个可以使用以下代码正常工作的列表,所以我知道在BLE管理器中一切正常:

List(bleManager.peripheralsDisp) { peripheral in
    Text(peripheral.displayName)
  }.frame(height: 300)

但是,用于选择器的相同代码不起作用:

Picker(selection: $selectedDevice, label: Text("")) {
    ForEach(self.bleManager.peripheralsDisp, id: \.self) { peripheral in
      Text(peripheral.displayName)
    }
  }
  .frame(width: 200, height: 40, alignment: .center)

任何有关如何使选择器选项动态更新的建议将不胜感激

编辑:

这是我的BLEManager.swift文件

import Foundation
import CoreBluetooth

struct PeripheralDisp: Hashable {
    let serialNo: Int
    let displayName: String
}

class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate {
        
    @Published var isSwitchedOn = false
    @Published var peripheralsDisp = [PeripheralDisp]()

    var myCentral: CBCentralManager!
    var myPeripheral: CBPeripheral!
    
    override init() {
        super.init()
        
        myCentral = CBCentralManager(delegate: self, queue: nil)
        myCentral.delegate = self
    }
    
    func centralManagerDidUpdateState(_ central: CBCentralManager) {
        if central.state == .poweredOn {
            isSwitchedOn = true
            startScanning()
        }
        else {
            isSwitchedOn = false
            stopScanning()
        }
    }
    
    func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
        
        var peripheralName: String = ""

        var peripheralSerialNo: Int = 0
        var peripheralDisplayName: String = ""
        
        if let name = advertisementData[CBAdvertisementDataLocalNameKey] as? String {
            peripheralName = name
        }
        else {
            peripheralName = "Unknown"
        }
                let newPeripheralDisp = PeripheralDisp(serialNo: newPeripheralDisp.count, displayName: peripheralDisplayName)
                peripheralsDisp.append(newPeripheralDisp) //peripheralDisplayName)

    }
    
    func startScanning() {
        print("StartScanning")
        myCentral.scanForPeripherals(withServices: nil, options: nil)
    }
    
    func stopScanning() {
        print("StopScanning")
        myCentral.stopScan()
    }
}

完整的ContentView.swift:

struct ContentView: View {
    
    @EnvironmentObject var viewRouter: ViewRouter
    @ObservedObject var bleManager = BLEManager()
    @State var selectedDevice = 0
    
    var body: some View {
        
        
        VStack(spacing: 10) {
                        
            Spacer()
         
            // Device Picker
            Picker(selection: $selectedDevice, label: Text("")) {
                ForEach(self.bleManager.peripheralsDisp, id: \.self) { peripheral in
                    Text(peripheral.displayName)
                }
            }
            .frame(width: 200, height: 40, alignment: .center)
            

            /*List(bleManager.peripherals) { peripheral in
                Text(peripheral.displayName)
            }.frame(height: 300)
            
            Spacer()*/
            
         }
    }
}

1 个答案:

答案 0 :(得分:0)

这里有几个问题。首先,SwiftUI的let c = { title :{ value: "developer" } , startDate:{ month:{ value:” jan”}} } 在静态内容和动态内容上的行为有所不同。如果您希望内容是动态的,请使模型符合ForEach并使用Identifiable的重载,该重载只需要序列ForEach。其次,您要更改列表,以使选择可能会随着项目的放入而改变。我想如果删除所选项目,您可以将选择重置为0。为此,您应该将选择内容移到Identifiable中而不是视图中。实际上,我认为这里概念上更简单的想法是使用列表而不是选择器。只需更新列表,然后在他们点击项目时将其选中即可。 (即列表不需要保持在选择器同时选择某些项目的想法。)