Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.6k views
in Technique[技术] by (71.8m points)

swiftui - View Does Not Reload When Observed Object Changed

I'm struggling with what I thought would be a pretty simple problem to solve. See below... I have a class - "Connect" - This is @Observable. Within Connect I have a property "theMessage" which is @Published.

I then have my ContentView which references the property "theMessage" When the app is launched the view loads OK but... When the button is the methods within Connect are triggered but the view does not reload.

I believe that the problem is in the "receive" method towards the bottom of "Connect" Within the closure of this method I can see I'm the debug.. incomingMessage received OK theMethod gets set OK But the view doesn't change

Any Help Or Ideas Would Be Appreciated

import Foundation
import Network


class Connect: ObservableObject {
    static let sharedInstance = Connect()

private var talking: NWConnection?
private var listening: NWListener?

@Published var theMessage = "Still No Message"

// DEFINE LISTENER
func listenUDP(port: NWEndpoint.Port) {
    do {
        self.listening = try NWListener(using: .udp, on: port)
        self.listening?.stateUpdateHandler = {(newState) in
            switch newState {
            case .ready:
            print("ready")
            default:
            break
            }
        }
        
        self.listening?.newConnectionHandler = {(newConnection) in
            newConnection.stateUpdateHandler = {newState in
                switch newState {
                case .ready:
                print("new connection")
                self.receive(on: newConnection)
                default:
                break
                }
            }
                
            newConnection.start(queue: DispatchQueue(label: "new client"))
            }
        } catch {
    print("unable to create listener")
    }
    self.listening?.start(queue: .main)
}// END OF FUNC - LISTEN TO UDP





// DEFINE ON RECEIVE
func receive(on connection: NWConnection) {
    connection.receiveMessage { (data, context, isComplete, error) in
        if let error = error {
            print(error)
            return
        }
        if let data = data, !data.isEmpty {
            let incomingString = String(decoding: data, as: UTF8.self)
            print("Incoming String -(incomingString)")
                DispatchQueue.main.async { [weak self] in
                    self?.objectWillChange.send()
                    self?.theMessage = incomingString
                    print(self?.theMessage ?? "Self Got Binned")
            }
        }
    }
    
}// END OF FUNC - RECEIVE




// DEFINE TALKER
func connectToUDP(hostUDP:NWEndpoint.Host,portUDP:NWEndpoint.Port) {
    self.talking = NWConnection(host: hostUDP, port: portUDP, using: .udp)
    self.talking?.stateUpdateHandler = { (newState) in
        switch (newState) {
            case .ready:
            break
            default:
            break
        }
    }
    self.talking?.start(queue: .main)
}// END OF DEFINE TALKER


// SEND A MESSAGE
func sendUDP(_ content: String) {
    let contentToSendUDP = content.data(using: String.Encoding.utf8)
    
    self.talking?.send(content: contentToSendUDP, completion: NWConnection.SendCompletion.contentProcessed(({ (NWError) in
        if (NWError == nil) {
            // code
        } else {
            print("ERROR! Error when data (Type: String) sending. NWError: 
 (NWError!) ")
        }
    })))
}

}// END OF CLASS - CONNECT


    import SwiftUI
import Network

struct ContentView: View {

@ObservedObject var connect = Connect.sharedInstance
let communication = Connect()

var body: some View {
    
    VStack {
        Text("Incoming Message - (self.connect.theMessage)")
            .padding(100)
            .onAppear(){
                // LISTENER
                let port2U = NWEndpoint.Port.init(integerLiteral: 1984)
                communication.listenUDP(port: port2U)
            }
   
        Button(action: {
            let host = NWEndpoint.Host.init("localhost")
            let port = NWEndpoint.Port.init("1984")
            self.communication.connectToUDP(hostUDP: host, portUDP: port!)
            self.communication.sendUDP("/cue/MyText/start")
        }) {
            Text("smoke")
        }
        
    }// END VSTACK
}// END OF BODY
}// END OF VIEW
question from:https://stackoverflow.com/questions/65845314/view-does-not-reload-when-observed-object-changed

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

This code in your Connect class creates a singleton instance

static let sharedInstance = Connect()

Then the View creates another instance with this

let communication = Connect()

One cannot see what the other is doing. It is like creating having 2 cars, 2 houses, 2 people.

Remove communication and replace with connect. Observe and use the Singleton.

struct ConnectView: View {

    @ObservedObject var connect = Connect.sharedInstance

    var body: some View {
        
        VStack {
            Text("Incoming Message - (self.connect.theMessage)")
                .padding(100)
                .onAppear(){
                    // LISTENER
                    let port2U = NWEndpoint.Port.init(integerLiteral: 1984)
                    connect.listenUDP(port: port2U)
                }
       
            Button(action: {
                let host = NWEndpoint.Host.init("localhost")
                let port = NWEndpoint.Port.init("1984")
                self.connect.connectToUDP(hostUDP: host, portUDP: port!)
                self.connect.sendUDP("/cue/MyText/start")
            }) {
                Text("smoke")
            }
            
        }// END VSTACK
    }// END OF BODY
}// END OF VIEW

It is good practice to make the initializer of a class private if you will have a Singleton pattern.

Add this to your Connect class to prevent this issue.

private init(){
    
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...