UIViewController dismiss issue

dismiss completion swift
uiviewcontroller dismiss detect
swift dismiss previous view controller
uiviewcontroller dismiss completion not called
dismiss view controller swift
uinavigationcontroller dismiss
dismiss modal view controller and present another
dismiss modal view controller swift 4

I want to wait until dismiss animation completes but I don't want to use many blocks in my code, so I wrote this function in UIViewController extension (almost like this worked several years ago for me):

func dismissAnimated() {
   var comleted: Bool = false
   self.dismiss(animated: true) {
      comleted = true
   }

   while !comleted {
      RunLoop.current.run(mode: RunLoop.Mode.common, before: Date.distantFuture)
   }
}

so now instead of:

viewController.dismiss(animated: true) {
    // code after completion
}

I was supposed to write:

viewController.dismissAnimated()
// code after completion

But it doesn't dismiss view controller and doesn't enter into completion block.

I tried different RunLoop modes, tried different dates, tried inserting RunLoop.current.run into while condition, it didn't work. Any ideas how to accomplish this?

Edit:

And it worked on iOS 9 or something like this (may be with some code changes, because I can't find my source code). I start RunLoop.current.run to avoid blocking main thread. For instance, if I put completed = true in DispatchQue.main.asyncAfter , it will work, the issue is with dismiss

I tried again because I was curious and this solution actually works for me:

@objc private func dismissTapped() {

    let dismissalTime = dismissAnimated()
    print("Dismissal took: %ld", abs(dismissalTime))

}

private func dismissAnimated() -> TimeInterval {

    let startDate = Date()

    var completed = false
    self.dismiss(animated: true) {
        completed = true
    }

    while !completed {
        RunLoop.current.run(mode: .default, before: .distantFuture)
    }

    return startDate.timeIntervalSinceNow

}

iOS 12.1.2 | Swift 4.2

UIViewController dismiss issue, I tried again because I was curious and this solution actually works for me: @objc private func dismissTapped() { let dismissalTime  The top-most view is dismissed using its modal transition style, which may differ from the styles used by other view controllers lower in the stack. If you want to retain a reference to the view controller'€™s presented view controller, get the value in the presentedViewController property before calling this method.

It doesn't dismiss because your while !completed loop has stalled the main thread and the UI update happens on the main thread. What is wrong with running whatever code you need to run inside the dismiss completion closure?

self.dismiss(animated: true) {
    runSomeCode()
}

Preventing memory leak when not dismissing modally-presented , leak when not dismissing modally-presented UIViewController in iOS The same problem was reported to Apple in 2015, but there is as yet  @nihilenz I was able to reproduce the issue you mentioned. The fix is pretty simple: we just need to disable interactions on the toViewController's view as well. That way, the dismiss button cannot be interacted with until the view animation comes to a complete stop. ashfurrow/UIViewController-Transitions-Example@nihilenz:masterashfurrow:master

If it's really just about not using blocks maybe this may be a solution?

override func viewDidDisappear(_ animated: Bool) {
    super.viewDidDisappear(animated)

    if self.navigationController?.isBeingDismissed ?? self.isBeingDismissed  {
        print("Dismissal completed...")
    }
}

View Controller Presentation Changes in iOS 13, Do my current apps run without issues on iOS 13? Apple have a Interactive dismissal of modally-presented view controller on iPhone XS. UIViewController – issue with custom dismiss transition (2) A few potential gotchas with dismissal of modally presented view controllers using custom transition animations: Add the presented ("to") view to the container, then bring the presented view front. Don't add the presenting view as you might remove it from its current superview.

Pushing, Popping, Presenting, & Dismissing ViewControllers, I recently found myself in a situation where I had presented a UINavigationController modally and then pushed UIViewControllers within the  DismissViewController only dismisses a controller that was presented. You "present" a view controller by calling PresentViewController ().

Dismissing modal view controller causes the screen to black out , Tap on "Present view controller"; Tap the "done" button; Black screen appears. I think I found the place where the problem seems to be. In iOS 8  Code Issues Pull requests Use PanGesture to dismiss view on UIViewController and UIView. uiview uiviewcontroller dismiss dismissible pangesture

5 breaking changes to check before building your app for iOS 13, If you have used modal presentation for view controller prior to iOS 13, This may cause issue if your application flow is to dismiss the modal  Calling presentedViewController.dismiss(animated:completion) will dismiss the childViewController. The childViewController is the current UIViewController that is being presented.

Comments
  • Thank you, it works, actually it works only when I tap, if I call dismissAnimated() from DispatchQueue.main, it doesn't work (dismiss works but completion never called), but I'll try to figure it out
  • because of improving archichecture decision I'd better use code without block, anyway the question is how to make this decision to work. And it worked on iOS 9 or something like this (may be with some code changes, because I can't find my source code). I run runLoop to avoid blocking main thread. For instance, if I put in DispatchQue.main.asyncAfter , it will work, the issue is with dismiss
  • No I need to accomplish the task using RunLoop because the code almost like this worked before
  • Actually found a solution that works. See new Answer.