【问题标题】:How to send a last message and close the socket when a SwiftUI view is dismissed?当 SwiftUI 视图被关闭时,如何发送最后一条消息并关闭套接字?
【发布时间】:2020-05-15 13:02:00
【问题描述】:

我有一个 SwiftUI 工作表视图,其中有一个处理 tcp 通信的 ObservedObject,当此工作表被关闭时,我需要它发送最后一条 tcp 消息,然后关闭套接字. onDisappear 事件似乎永远不会被触发(编辑:找到了罪魁祸首,因为我使用 UIHostingController 呈现工作表,仍然需要解决方案) 我已经尝试将它放在表单、导航视图中,尝试为其创建一个新堆栈,但没有任何效果。因此,我尝试使用我的 ObservedObject deinit,但是如果我在关闭视图后尝试快速重新打开视图,则会出现错误的访问错误。

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

来自我使用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()
}

编辑:在下面添加视图代码

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

这些 onDisappear 都不适合我,ScheduleForm 行中的行是唯一一个甚至对我触发的行,但它会在创建工作表时触发每次我将一行滚动到视线之外,但在我关闭工作表时不会。

【问题讨论】:

  • 什么会消除视图?它是否连接到它上面的某个绑定?
  • 你需要显示你的工作表视图,你在哪里调用 onDisappear
  • @jnblanchard 其工作表视图可以通过滑动关闭
  • @ErnistIsabekov 我刚刚用视图代码更新了它
  • 查看鳕鱼看起来没问题 onDisappear 应该在向下滑动时触发

标签: swift swiftui deinit network-framework


【解决方案1】:

解决办法:

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

【讨论】:

    【解决方案2】:

    我做的第一件事是改变你的函数签名,使用一个闭包来完成成功和错误。

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

    然后我们可以在 onDisappear 修饰符中使用它。完成后关闭连接。

    struct ContentView: View {
    
      var body: some View {
    
        Text("Hello World").onDisappear {
          sendMsg("last msg", completion: { completed in
            close()
          })
        }
    
      }
    }
    

    【讨论】:

    • 我会检查所有异常情况并返回错误信息
    • onDisappear 事件对我来说根本无法正常工作,我使用的是 Xcode 11.3.1。当工作表被关闭时它会触发吗?
    【解决方案3】:

    我经常做的事情是这样的:

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

    }

    【讨论】:

    • .onDisappear 永远不会在工作表被滑开时触发,可能是因为我使用的是 UIHostingController 吗?
    【解决方案4】:

    我有这个非常粗略的测试工作。 显示一个工作表,当您滑动时,会触发 onDisappear 并执行 doExit 函数。对 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()
    }
    }
    

    【讨论】:

    • 刚刚试了一下,如果工作表是从 SwiftUI 视图调用的,它可以工作,但是当它使用 UIHostingController self.present(UIHostingController(rootView: TestView(scheduleManager: ["one", "two"])), animated: true, completion: nil)它调用时,它不会工作。
    猜你喜欢
    • 1970-01-01
    • 2011-05-17
    • 1970-01-01
    • 2021-08-03
    • 1970-01-01
    • 1970-01-01
    • 2015-01-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多