Как отправить последнее сообщение и закрыть сокет при закрытии представления SwiftUI?

У меня есть представление листа SwiftUI с ObservedObject, которое обрабатывает tcp-связь, когда этот лист закрывается, мне нужно, чтобы он отправил последнее tcp-сообщение, а затем закрыл сокет. Кажется, что событие onDisappear никогда не запускается (Edit: выяснилось, в чем причина, потому что я представляю лист с помощью UIHostingController, все еще нужно решение ) Я попытался поместить его в форму, представление навигации, попытался создать для него новый стек, ничего не сработало. Итак, я попытался использовать деиницирование ObservedObject, но это дает мне ошибку плохого доступа, если я пытаюсь быстро снова открыть представление после его закрытия.

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 - единственная, которая даже срабатывает для меня, но она срабатывает при создании листа и каждый раз, когда я прокрутите строку с глаз долой, но не тогда, когда я закрываю лист.


person Watermamal    schedule 29.01.2020    source источник
comment
Что отвергает мнение? Это связано с какой-то привязкой над ним?   -  person jnblanchard    schedule 30.01.2020
comment
Вам нужно показать вид листа, где вы вызываете onDisappear   -  person Ernist Isabekov    schedule 30.01.2020
comment
@jnblanchard - его вид листа, который можно закрыть смахиванием   -  person Watermamal    schedule 30.01.2020
comment
@ErnistIsabekov Я только что обновил код просмотра   -  person Watermamal    schedule 30.01.2020
comment
Просмотр трески выглядит нормально на "Исчезновение" должно срабатывать при смахивании вниз   -  person Ernist Isabekov    schedule 30.01.2020


Ответы (4)


Решение:

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
    }
}
person Watermamal    schedule 31.01.2020

Первое, что я сделал, это изменил подпись вашей функции, чтобы использовать одно закрытие для успеха и завершения ошибки.

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

  }
}
person jnblanchard    schedule 29.01.2020
comment
Я бы проверил все на исключение и вернул сообщение об ошибке, если бы получил - person Ernist Isabekov; 30.01.2020
comment
Событие onDisappear у меня просто не работает должным образом, я использую Xcode 11.3.1. Срабатывает ли у вас, когда лист закрывается? - person Watermamal; 30.01.2020

я часто делаю что-то вроде этого:

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

}

person workingdog    schedule 30.01.2020
comment
.onDisappear никогда не срабатывает, когда лист удаляется, может быть, потому, что я использую UIHostingController? - person Watermamal; 30.01.2020

У меня работает этот очень грубый тест. Представлен лист, и когда вы проводите пальцем по экрану, срабатывает 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()
}
}
person workingdog    schedule 30.01.2020
comment
Только что попробовал, он работает, если лист вызывается из представления SwiftUI, но когда он вызывается с помощью UIHostingController self.present(UIHostingController(rootView: TestView(scheduleManager: ["one", "two"])), animated: true, completion: nil)it, работать не будет. - person Watermamal; 31.01.2020