Managing modal states in UIKit

One of the common use cases I found when building apps is presenting and dismissing modals. The steps are more or less like this

  1. The user taps a button
  2. Depending on the business logic, the app might show a modal and the user can dismiss them.

While this is an easy problem with SwiftUI that can be solved with bindings, it's still not that convenient in UIKit.

This is what I usually do to handle such use case:

  1. Use a boolean flag in the state to identify whether the modal dialog is shown.
  2. Pass the store to the modal view controller, and send a dismiss action on either deinit or viewWillDisappear

While this simple approach works, it gets quite tedious if you have lots of modals, still not as convenient as SwiftUI.

There are two solutions I can think of to solve this:

  1. Create a wrapper view controller that has dismiss callbacks.
viewStore.showModal.sink { showModal in
  if showModal {
    let wrapped = MyModalViewController()
    self.present(ModalWrapperController(wrapped, onDismiss: { viewStore.send(.dismiss) }), animated: true)
  }
}
  1. Add the capability to subscribe to actions in the ViewStore. This approach looks simpler, but I'm not sure whether it is a good approach for not.
// don't event need to store the modal state for this
viewStore.actions.compactMap(/Action.showModal).sink {
  self.present(MyModalViewController(), animated: true)
}

Any thoughts on this? I hope there are better solutions to solve this problem.

3 Likes