I have a WKInterfaceController with a WKInterfaceTable that lists some events a user has recorded in my app.
A user can tap a row of the table to see more details about that event. To accomplish this, I've overridden contextForSegue(withIdentifier:in:rowIndex:) on the WKInterfaceController that contains the table, so tapping a row modally presents a detail view of that row in a new WKInterfaceController called EventDetailController.
The modal presentation is defined on the Storyboard. I can't use push presentation because the WKInterfaceController with the WKInterfaceTable is a page among multiple instances of WKInterfaceController at the top level of my app.
Here's the main issue:
Within the EventDetailController, there's a Delete button to destroy the record that the table row represents.
When a user taps the Delete button, I present an alert that allows the user to confirm or cancel the delete action.
Once the user confirms the record deletion, I want to dismiss the EventDetailController since it's no longer relevant, because it represents a deleted record.
Here's the IBAction defined on EventDetailController that gets called when the Delete button is tapped:
@IBAction func deleteButtonTapped(_ sender: WKInterfaceButton) {
let deleteAction = WKAlertAction(title: "Delete", style: .destructive) {
// delete the record
// as long as the delete was successful, dismiss the detail view
self.dismiss()
}
let cancelAction = WKAlertAction(title: "Cancel", style: .cancel) {
// do nothing
}
presentAlert(withTitle: "Delete Event",
message: "Are you sure you want to delete this event?",
preferredStyle: .alert,
actions: [deleteAction, cancelAction])
}
The problem is that watchOS doesn't seem to allow this. When testing this code, the EventDetailController does not dismiss. Instead, an error message is logged in the console:
[WKInterfaceController dismissController]:434: calling dismissController from a WKAlertAction's handler is not valid. Called on <Watch_Extension.EventDetailController: 0x7d1cdb90>. Ignoring
I've tried some weird workarounds to try to trick the EventDetailController into dismissing, like firing a notification when the event is deleted and dismissing the EventDetailController from a function that's called from an observer of the notification, but that doesn't work either.
At this point I'm thinking there's some correct way I'm supposed to be able to dismiss a WKInterfaceController, or in other words reverse the contextForSegue(withIdentifier:in:rowIndex:) call, but I don't know what it is.
When I call dismiss() directly in the IBAction, instead of in a WKAlertAction handler, it works fine, but I don't like this implementation since it doesn't allow the user to confirm the action first.
I feel like an idiot, but I figured out the solution.
The answer was in Apple's
WKInterfaceController.dismiss()documentation the whole time (emphasis added):All I had to do differently was call
self.dismiss()on the main thread.Here's my updated code for the delete action, which now works as expected:
Hopefully this will save someone else some troubleshooting time!