简体   繁体   English

当 SwiftUI 视图被关闭时,如何发送最后一条消息并关闭套接字?

[英]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.我有一个带有ObservedObjectSwiftUI 工作表视图,用于处理 tcp 通信,当该工作表被解除时,我需要它发送最后一条 tcp 消息,然后关闭套接字。 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. onDisappear事件似乎从未被触发(编辑:找出了罪魁祸首,因为我正在使用UIHostingController呈现工作表,仍然需要一个解决方案)我试过把它放在表单、导航视图中,尝试创建一个新堆栈为此,没有任何效果。 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.所以我尝试使用我的ObservedObject deinit 但是如果我在关闭视图后尝试快速重新打开视图,这会给我一个错误的访问错误。

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

from my connection class that uses Network Framework来自我使用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.这些onDisappear 都不适合我, ScheduleForm行中的行是唯一一个甚至为我触发的行,但它在创建工作表时以及每次我滚动一行看不见时触发,但在我关闭工作表时不会触发.

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
    }
}

The first thing I did was change your function signature to use a single closure for success and error completion.我做的第一件事是更改您的函数签名以使用单个闭包来实现成功和错误完成。

func sendMsg(_ message: String, completion: ((Bool) ->())? = nil)

Then we can use that inside the onDisappear modifier.然后我们可以在 onDisappear 修饰符中使用它。 On completion close the connection.完成后关闭连接。

struct ContentView: View {

  var body: some View {

    Text("Hello World").onDisappear {
      sendMsg("last msg", completion: { completed in
        close()
      })
    }

  }
}

what I often do is something like this:我经常做的是这样的:

struct ScheduleView: View {

@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>

@ObservedObject var scheduleManager = ScheduleManager() 

var body: some View {
    NavigationView {
        Form {
            ForEach(scheduleManager.timers) { timer in
                ScheduleForm(scheduleManager: self.scheduleManager, timer: timer)
            }
        }
    }.onDisappear(perform: doExit)
     .navigationBarTitle(Text("Schedule"), displayMode: .inline)
}

func doExit() {

  // do your closing etc ... here

  // then to go back to the previous view
  self.presentationMode.wrappedValue.dismiss()
}

} }

I have this very crude test working.我有这个非常粗略的测试工作。 A sheet is presented and when you swipe, onDisappear is triggered and perform the doExit function.显示一个工作表,当您滑动时,将触发 onDisappear 并执行 doExit 功能。 Don't know anything about UIHostingController.对 UIHostingController 一无所知。

struct ContentView: View {
@State var testArray = ["one", "two", "three"]
@State var showMe = false

var body: some View {
    Button(action: { self.showMe = true}) {
        Text("Press button")
    }.sheet(isPresented: $showMe, onDismiss: {self.showMe = false}) { TestView(scheduleManager: self.testArray) }
}
}

struct TestView: View {
@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
@State var scheduleManager: [String]

var body: some View {
    NavigationView {
        Form {
            ForEach(scheduleManager, id: \.self) { timer in
                Text(timer)
            }
        }
    }.onDisappear(perform: doExit)
}

func doExit() {
    print("-----> TestView doExit")
    // then to go back to the previous view
    self.presentationMode.wrappedValue.dismiss()
}
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM