'Using @EnvironmentObject properly
I am just trying to get my updated value to display in my application after it receives a new value from bluetooth core. I know the value in the class is updating properly because I can see it in my print statement. My problem is that my @EnvironmentObject itself is not updating in the view so its always showing "No Value Yet"
Any help would be appreciated I am new to IOS!
import SwiftUI
import CoreBluetooth
import UIKit
let weightScaleCBUUID = CBUUID(string: "0x181D")
let massPoundCharacteristicCBUUID = CBUUID(string: "0x27B8")
class HRMViewController: UIViewController, ObservableObject {
@IBOutlet weak var bodySensorLocationLabel: UILabel!
var centralManager: CBCentralManager!
var weightPeripheral: CBPeripheral!
@Published var willWork: String = "No Value Yet"
override func viewDidLoad() {
super.viewDidLoad()
centralManager = CBCentralManager(delegate: self, queue: nil)
// Make the digits monospaces to avoid shifting when the numbers change
}
}
extension HRMViewController: CBCentralManagerDelegate {
func centralManagerDidUpdateState(_ central: CBCentralManager) {
switch central.state {
case .unknown:
print("central.state is .unknown")
case .resetting:
print("central.state is .resetting")
case .unsupported:
print("central.state is .unsupported")
case .unauthorized:
print("central.state is .unauthorized")
case .poweredOff:
print("central.state is .poweredOff")
case .poweredOn:
print("central.state is .poweredOn")
centralManager.scanForPeripherals(withServices: [weightScaleCBUUID])
@unknown default:
print("Something is completely wrong here")
}
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral,
advertisementData: [String: Any], rssi RSSI: NSNumber) {
print(peripheral)
// copy the peripheral instance
weightPeripheral = peripheral
weightPeripheral.delegate = self
centralManager.stopScan()
centralManager.connect(weightPeripheral)
}
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
if peripheral == weightPeripheral {
print("Connected!")
weightPeripheral.discoverServices([weightScaleCBUUID])
} else {
print("Something went wrong in didConnect")
}
}
}
extension HRMViewController: CBPeripheralDelegate {
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
guard let services = peripheral.services else { return }
for service in services {
print(service)
peripheral.discoverCharacteristics([massPoundCharacteristicCBUUID], for: service)
}
}
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic,
error: Error?) {
switch characteristic.uuid {
case massPoundCharacteristicCBUUID:
if let CurrWeightValue = String(bytes: characteristic.value![1...6], encoding: .utf8) {
// print(CurrWeightValue)
willWork = CurrWeightValue
print(willWork)
// bodySensorLocationLabel!.text = CurrWeightValue
} else {
print("not a valid UTF-8 sequence")
}
// let weightValue = weightHelper(from: characteristic)
// // print(weightValue)
// peripheral.setNotifyValue(true, for: characteristic)
// bodySensorLocationLabel.text = weightValue
default:
print("Unhandled Characteristic UUID: \(characteristic.uuid)")
}
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService,
error: Error?) {
guard let characteristics = service.characteristics else { return }
for characteristic in characteristics {
if characteristic.properties.contains(.notify) {
print("\(characteristic.uuid): properties contains .notify")
peripheral.setNotifyValue(true, for: characteristic)
}
}
}
}
struct HRMViewControllerRepresented: UIViewControllerRepresentable {
var centralManager: CBCentralManager!
var weightPeripheral: CBPeripheral!
weak var bodySensorLocationLabel: UILabel!
var willWork = ""
func makeUIViewController(context: Context) -> HRMViewController {
return HRMViewController()
}
func updateUIViewController(_ uiViewController: HRMViewController, context: Context) {
uiViewController.centralManager = centralManager
uiViewController.weightPeripheral = weightPeripheral
uiViewController.bodySensorLocationLabel = bodySensorLocationLabel
uiViewController.willWork = willWork
uiViewController.viewDidLoad()
}
}
struct SessionsView: View {
@EnvironmentObject var userController: HRMViewController
var body: some View {
VStack{
Text("Howdy Number \(userController.willWork)").padding()
HRMViewControllerRepresented()
}
}
}
struct SessionsView_Previews: PreviewProvider {
static var previews: some View {
SessionsView().environmentObject(HRMViewController())
}
}
struct ContentView: View {
var body: some View {
TabView {
HomeView()
.tabItem() {
Image("home-icon")
.renderingMode(.template)
Text("Home")
}
SessionsView().environmentObject(HRMViewController())
.tabItem() {
Image("sessions-icon")
.renderingMode(.template)
Text("Sessions")
}
ReportsView()
.tabItem() {
Image("reports-icon")
.renderingMode(.template)
Text("Reports")
}
SettingsView()
.tabItem() {
Image("settings-icon")
.renderingMode(.template)
Text("Settings")
}
}
}
}
Solution 1:[1]
Turns out it was very simple once I started implementing this protocol: Pass variable from UIViewController to SwiftUI View
Here is my final implementation using MVVM:
class SharedViewModel: ObservableObject {
@Published var myString = "---"
@Published var centralManager: CBCentralManager!
@Published var weightPeripheral: CBPeripheral!
}
//Not an extension
struct UIKitViewController_UI: UIViewControllerRepresentable {
typealias UIViewControllerType = WSViewController
var sharedVM: SharedViewModel
func makeUIViewController(context: Context) -> WSViewController {
return WSViewController(vm: sharedVM)
}
func updateUIViewController(_ uiViewController: WSViewController, context: Context) {
}
}
//My bluetooth Class
class WSViewController: UIViewController {
let sharedVM: SharedViewModel
var weightPeripheral: CBPeripheral!
init(vm: SharedViewModel) {
self.sharedVM = vm
super.init(nibName: nil, bundle: nil)
Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { timer in
self.methodThatChangeValueOfString()
}
}
...
// then used in the view struct like this
struct SessionsView: View {
@StateObject var sharedVM: SharedViewModel = SharedViewModel()
@EnvironmentObject var myWeights: StoredWeights
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 |