swiftswiftuideinitnetwork-framework

How to send a last message and close the socket when a SwiftUI view is dismissed?


I have a SwiftUI sheet view with an ObservedObject that handles tcp communication, when this sheet gets dismissed I need it to send a last tcp message and then close the socket. The onDisappear event never seems to get triggered (Edit: found out the culprit its because I'm presenting the sheet using a UIHostingController, still need a solution) I've tried putting it I the form, navigation view, tried creating a new stack for it, nothing worked. So I've tried using my ObservedObject deinit but this gives me a bad access error if I try to reopen the view fast after closing it.

deinit {
    let msg = getUpdatedTimersString()
    self.connection.sendMsg(msg, success: connection.close)
}

from my connection class that uses Network Framework

func sendMsg(_ message: String, success: @escaping () -> Void = { }, error: @escaping () -> Void = { }) {
        let msg = message + "\r\n"
        let data: Data? = msg.data(using: .utf8)
        debugPrint("Sending: \(msg)")
        connection.send(content: data, completion: .contentProcessed { (sendError) in
            if let sendError = sendError {
                self.debug("\(sendError)")
                error()
            } else {
                success()
            }
        })
}

func close() {
        connection.cancel()
}

Edit: adding the view code below

struct ScheduleView: View {
    @ObservedObject var scheduleManager = ScheduleManager() // This handles the tcp communication, the deinit you see above is from this

    var body: some View {
        NavigationView {
            Form {
                ForEach(scheduleManager.timers) { timer in
                    ScheduleForm(scheduleManager: self.scheduleManager, timer: timer).onDisappear { debugPrint("schedule form row disappeared") } // This is just a view that adds a section header and a DatePicker to the form for each timer
                }
            }.onDisappear { debugPrint("form disappeared") }

            .navigationBarTitle(Text("Schedule"), displayMode: .inline)
        }.onDisappear() { debugPrint("nav disappeared") }
    }
}

None of these onDisappear work for me, the one in the ScheduleForm rows is the only one that even triggers for me, but it triggers when the sheet is created and every time I scroll a row out of sight, but not when I dismiss the sheet.


Solution

  • Solution:

    final class ScheduleController: UIHostingController<ScheduleView> {
        required init?(coder: NSCoder) {
            super.init(coder: coder, rootView: ScheduleView())
        }
    
        init() {
            super.init(rootView: ScheduleView())
        }
        override func viewWillDisappear(_ animated: Bool) {
            rootView.scheduleManager.updateTimers() // this sends the last message
        }
    
        override func viewDidDisappear(_ animated: Bool) {
            rootView.scheduleManager.connection.close // this closes the connection
        }
    }