Дождаться результата таблицы действий, прежде чем продолжить?

#swiftui

#swiftui

Вопрос:

У меня есть кнопка внутри .contextMenu (т. Е. Отметить как оплаченную)

Первое, что он делает, это переключает таблицу действий, чтобы выбрать способ оплаты. Сразу же следует некоторый код для добавления записи в календарь пользователей через EventKit.

Моя проблема в том, что я хочу, чтобы таблица действий возвращала результат ДО выполнения кода EventKit.

Как вы заставляете его ждать?

Свойства:

 @State private var showPaymentSheet = false
@State private var paymentType = ""

var actionSheet: ActionSheet {
    ActionSheet(title: Text("Payment Method"), buttons: [
        .default(Text("💷 Cash")) { paymentType = "💷 Cash" },
        .default(Text("💳 Bank Transfer")) { paymentType = "💳 Bank" },
        .default(Text("🅿️ PayPal")) { paymentType = "🅿️ PayPal" },
        .default(Text("🖋 Cheque")) { paymentType = "🖋 Cheque" },
        .cancel()
    ])
}
  

Тело:

 .contextMenu {

Button(action: {
    
**// Run This ActionSheet FIRST and get result of (paymentType) **

    self.showPaymentSheet.toggle()

**// ONLY then continue with below **
   
    let thisDay = self.selectDate.selectedDate
    let eventStore = EventsRepository.shared.eventStore
    let payment = EKEvent(eventStore: eventStore)
    payment.calendar = event.calendar
    payment.startDate = event.startDate
    payment.endDate = event.endDate
    payment.title = "💰(event.title!)"
    payment.notes = "(event.notes!)nPaid: (Date().dateType(dateFormat: "EEE MMM dd yyyy @ HH:mm b " )) by (paymentType)"
    payment.location = "(event.location!)"

    do {
        try eventStore.save(payment, span: .thisEvent)//i - Save Updated (event)
        try EventsRepository.shared.eventStore.remove(event, span: .thisEvent)
        EventsRepository.shared.loadAndUpdateEvents(selectedDate: thisDay)

    }   catch {
        print("Failled to cancel event")
    }
    NotificationCenter.default.post(name: .eventsDidChange, object: nil)
}){
    HStack {
        Text("Mark as Paid")
            .font(Font.custom("ChalkboardSE-Bold", size: 32))
        Image("payment")
            .renderingMode(.original)
    }
}.actionSheet(isPresented: $showPaymentSheet, content: {
                self.actionSheet})
}
  

Ответ №1:

Вы можете использовать onReceive .

Вот простая демонстрация:

 struct ContentView: View {
    @State private var showPaymentSheet = false
    @State private var paymentType = ""

    var body: some View {
        Button("Choose payment") {
            self.showPaymentSheet.toggle()
        }
        .actionSheet(isPresented: $showPaymentSheet) {
            self.actionSheet
        }
        .onReceive(Just(paymentType)) { // <- add here
            guard !$0.isEmpty else { return }
            self.someOtherFunc()
        }
    }

    var actionSheet: ActionSheet {
        ...
    }

    func someOtherFunc() {
        print(paymentType)
    }
}
  

Тем не менее, я рекомендую перенести логику в отдельный класс и сохранить представление чистым. Также почему paymentType = "" ? Если это может быть не установлено, вам, вероятно, следует использовать nil вместо этого. И почему вам нужно, чтобы это было наблюдаемым в первую очередь? Вы также можете создать отдельное перечисление для типов платежей.

С вышеуказанными изменениями мы можем написать обновленный пример:

 enum PaymentType: String {
    case cash = "💷 Cash"
    case bank = "💳 Bank Transfer"
    ...
}

class PaymentHandler: ObservableObject {
    func pay(_ paymentType: PaymentType) {
        // print(paymentType.rawValue) // do something with `paymentType`
    }
}
  
 struct ContentView: View {
    @ObservedObject private var vm = ViewModel()
    @State private var showPaymentSheet = false

    var body: some View {
        Button("Choose payment") {
            self.showPaymentSheet.toggle()
        }
        .actionSheet(isPresented: $showPaymentSheet) {
            self.actionSheet
        }
    }

    var actionSheet: ActionSheet {
        ActionSheet(title: Text("Payment Method"), buttons: [
            .default(Text(PaymentType.cash.rawValue)) { self.vm.pay(.cash) },
            .default(Text(PaymentType.bank.rawValue)) { self.vm.pay(.bank) },
            .cancel(),
        ])
    }
}