SwiftUI 和 CocoaMQTT 服务器 - 如何在不使用按钮的情况下进行连接?

问题描述 投票:0回答:1

我正在构建一个应用程序,它将通过 Raspberry Pi 提供的 Wi-Fi 读取值,并且我正在使用 MQTT 服务器和客户端。使用 UIKit 很简单,并且在对 matt 服务器/客户端的控制方面,委托方法非常用户友好。 但是,我正在使用 SwiftUI 构建应用程序,我有风速计(风传感器)显示屏的视图,我想获取 NMEA 并使用字符串中的值将它们显示在视图上。在我看来,我正在努力在不使用按钮的情况下与经纪人保持联系。我希望在加载视图时进行连接、订阅主题、获取消息(通过 wi-fi 不断广播)并显示它们。 当我使用按钮时,这似乎很好,但如果我使用 onAppear 方法,它无法连接到 RPi 并接收消息。有什么好的建议吗?这是我的代码:

//
//  ContentView.swift
//  ExtasyCompleteNavigation
//
//  Created by Vasil Borisov on 13.06.23.
//

import SwiftUI
import CocoaMQTT

struct ContentView: View {
    
    let mqttClient = CocoaMQTT(clientID: "Navigation", host: "raspberrypi.local", port: 1883)
    
    var body: some View {
        
        VStack {
            AnemometerView()
            Button("Connect"){
                    _ = mqttClient.connect()
                }
            Button("Subscribe"){
                mqttClient.subscribe("windData")
            }
            Button("Get Message"){
                mqttClient.didReceiveMessage = { mqtt, message, id in
                    print((message.string!))
                }
            }
            Button("Disconnect"){
                mqttClient.disconnect()
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

我尝试使用 .onAppear 方法,因此一旦加载视图它就会连接,但它似乎不起作用。如果我检查服务器日志,它会告诉我由于协议错误而无法连接。有人经历过吗?

编辑-1 这是我在 .onAppear() 方法中使用的代码。我知道如果我先连接,然后在 didConnectAck 方法中订阅该主题,然后以某种方式在 didReceiveMessage 闭包中接收消息,效果会更好。 我就是不知道怎么办? 是否有任何解决方法可以模仿我过去在 UIKit 中使用的委托方法?或者更好的方法?

//
//  ContentView.swift
//  ExtasyCompleteNavigation
//
//  Created by Vasil Borisov on 13.06.23.
//

import SwiftUI
import CocoaMQTT

struct ContentView: View {
    
    let mqttClient = CocoaMQTT(clientID: "Navigation", host: "raspberrypi.local", port: 1883)
    
    var windAngle = NavigationData()
    
    var body: some View {
        
        VStack {
            AnemometerView()
                .onAppear(){
                    _ = mqttClient.connect()
                    mqttClient.subscribe("windData")
                    mqttClient.didReceiveMessage = { mqtt, message, id in
                        if let safeMessage = message.string {
                            windAngle.windAngleString = safeMessage
                            print(windAngle.windAngleString)
                            print(windAngle.windAngleTest)
                        }
                    }
                }
//            Button("Connect"){
//
//                }
//            Button("Subscribe"){
//
//            }
//            Button("Get Message"){
//
//            }
            Button("Disconnect"){
                mqttClient.disconnect()
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
swiftui raspberry-pi mqtt raspberry-pi3 cocoamqtt
1个回答
0
投票

Is there any work arounds which will mimic delegate methods as I used to use in UIKit? Or better way?

这是我使用 MQTT 连接到 Raspberry Pi 的方法(未经测试)。

这里的重要部分是:将逻辑与 UI 分开,因此使用

MQTTManager
和 让这个
MQTTManager
成为
CocoaMQTTDelegate
以及
ObservableObject
用于收听收到的消息。

struct ContentView: View {
    @StateObject var mqttManager = MQTTManager() // <--- here
    
    var body: some View {
        VStack {
            Text(mqttManager.message)  // <-- for testing
            // AnemometerView()
            Button("Disconnect"){
                mqttManager.mqttClient.disconnect()
            }
        }
        .onAppear {
            mqttManager.mqttClient.connect()
            mqttManager.mqttClient.subscribe("windData")
        }
    }
}

// something like this
class MQTTManager: ObservableObject, CocoaMQTTDelegate {    // <--- here
    
    let mqttClient = CocoaMQTT(clientID: "Navigation", host: "raspberrypi.local", port: 1883)
    
    @Published var message = ""
    
    init() {
        // ....
        mqttClient.keepAlive = 60
        mqttClient.delegate = self  // <--- here
    }
    
    // .... CocoaMQTTDelegate functions ....

    func mqtt(_ mqtt: CocoaMQTT, didSubscribeTopics success: NSDictionary, failed: [String]) {
        print("topic: \(success)")
    }
    
    func mqtt(_ mqtt: CocoaMQTT, didUnsubscribeTopics topics: [String]) {
        print("topic: \(topics)")
    }
    
    func mqtt(_ mqtt: CocoaMQTT, didConnectAck ack: CocoaMQTTConnAck) {
        print("ack: \(ack)")
    }
    
    func mqtt(_ mqtt: CocoaMQTT, didPublishMessage message: CocoaMQTTMessage, id: UInt16) {
        print("message published: \(message.string.description), id: \(id)")
    }
    
    func mqtt(_ mqtt: CocoaMQTT, didPublishAck id: UInt16) {
        print("id: \(id)")
    }
    
    func mqtt(_ mqtt: CocoaMQTT, didReceiveMessage message: CocoaMQTTMessage, id: UInt16) {
        print("message received: \(message.string.description), id: \(id)")
        if let str = message.string { // <--- here or something like this
            self.message = str
        }
    }
    
    func mqtt(_ mqtt: CocoaMQTT, didSubscribeTopics success: NSDictionary, failed: [String]) {
        print("didSubscribeTopics")
    }
    
    func mqtt(_ mqtt: CocoaMQTT, didUnsubscribeTopic topic: String) {
        print("didUnsubscribeTopic")
    }
    
    func mqttDidPing(_ mqtt: CocoaMQTT) {
    }
    
    func mqttDidReceivePong(_ mqtt: CocoaMQTT) {
    }
    
    func mqttDidDisconnect(_ mqtt: CocoaMQTT, withError err: Error?) {
        print("\(err.description)")
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.