Chapter 8: Presenting a view controller as a Future

Hello, I have been trying the code related to the presentation of the Alert view controller as a Future, and I have some questions.

In order to dismiss the presented alert, you suggest to include a handleEvents(receiveCancel:) on the publisher:
func alert(title: String, text: String?) -> AnyPublisher<Void, Never> {
let alertVC = UIAlertController(title: title,
message: text,
preferredStyle: .alert)

    return Future { resolve in
      alertVC.addAction(UIAlertAction(title: "Close",
                                      style: .default) { _ in
        resolve(.success(()))
      })

      self.present(alertVC, animated: true, completion: nil)
    }
    .handleEvents(receiveCancel: {
        print("Received cancel Event")
       self.dismiss(animated: true)
    })
    .eraseToAnyPublisher()
  }

However, I do not see that the cancelation event gets triggered. In fact, we could completely remove the dismissal of the view, and we get the same behavior, the view gets dismissed as well. The only way I have managed to execute the cancellation handler is by not storing it in the subscriptions on the MainViewController. Is this the intended behavior, or is there something I am missing here?

1 Like

@freak4pc Can you please help with this when you get a chance? Thank you - much appreciated! :]

The cancellation event would be triggered if for some reason the viewController that presenter the alert and holds the subscriptions Set would get de-allocated. For example if viewController was removed from the navigation stack(or if it was dismissed, if it was modally presented ):

For example it should work if you try something like this in the viewDidLoad of the PhotosViewController:

        DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
            self.navigationController?.popViewController(animated: true)
        }
        self.alert("Finished with id").sink(receiveValue: { _ in }).store(in: &subscriptions)

But it will not work because, the following closure holds a store reference to the viewController (self)

Moreover in the above scenario (after the viewController is poped) you try and tap the alert button the App will crash. This could possible be a combine bug, since i suspect the de-allocation starts before the Future finishes its operations. This is evident if you try and capture a weak self reference in the handleEvents closure [weak self] () in . You will see that the closure is called after the self is de-allocated (is it nil). I have not solution for this.

This sounds a bit strange - I remember testing a ton of different scenarios when I wrote this code. I’ll have a look in the coming days and let you know

1 Like