我正在构建一个应用程序,它将通过 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()
}
}
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)")
}
}