1

The following code works on all the devices simulators I have access. However, some users reported the issue that leads me to think the completion block is not being called in some situation. I am out of idea at this moment. Any suggestion?

CATransaction.begin()
CATransaction.setCompletionBlock {
  self.performSegue(withIdentifier: "ContractViewController", sender: sender.companyJob)
}

self.navigationController?.popViewController(animated: true)
CATransaction.commit()

BTW, what I wanted to achieve is to have the pop and push screen transition animations. At this point, I am open for any solution or workaround. Thanks in advance.

Extra document from doc:

/* Accessors for the "completionBlock" per-thread transaction property.
 * Once set to a non-nil value the block is guaranteed to be called (on
 * the main thread) as soon as all animations subsequently added by
 * this transaction group have completed (or been removed). If no
 * animations are added before the current transaction group is
 * committed (or the completion block is set to a different value), the
 * block will be invoked immediately. Added in Mac OS X 10.6. */
Sean
  • 2,967
  • 2
  • 29
  • 39
  • is completion on main thread? – E.Coms Jan 30 '19 at 17:06
  • Why not using the navigation controller delegate ? – GaétanZ Jan 30 '19 at 17:09
  • So the idea is to perform the segue after the animated pop completes? If so, that’s not how to do it. It is a common misconception but there are correct techniques here too: https://stackoverflow.com/questions/12904410/completion-block-for-popviewcontroller – matt Jan 30 '19 at 17:10
  • @E.Comms, per doc, the completion block is to be called on main thread. – Sean Jan 30 '19 at 17:33
  • @GaetanZ: I thought navigation controller doesn't have delegate for my purpose. Would you please elaborate? – Sean Jan 30 '19 at 17:34
  • @matt my code actually were from the accepted answer in the link you pointed out. Would you please elaborate the right technique? Really appreciated! – Sean Jan 30 '19 at 17:35
  • What about "navigationController:didShowViewController:animated:" ? It is called when the view controller under the current is shown. – GaétanZ Jan 30 '19 at 17:37
  • Right, but as I said, it's a common misconception but it's not the right way. The answer may be accepted by the original poster, but that doesn't make it right. Look at some of the other answers. They show you some right ways. You get the needed callbacks through the delegate or through the view controller's transition controller. – matt Jan 30 '19 at 18:16
  • Thanks matt. I tried another answer using navigationController.transitionCoordinator.animate completion block. It appears to work. Do you think that is the right technique using navigationController.transitionCoordinator.animate completion block? – Sean Jan 30 '19 at 18:31
  • 1
    Yes, that's far better. – matt Jan 30 '19 at 18:31
  • Or you could just move the work into the v.c.'s `viewDidAppear` which isn't called until the animation is over. – matt Jan 30 '19 at 18:36
  • 3rd option, actually pretty good option above: this is simple enough with a flag for this particular path in viewDidAppear. – Sean Jan 30 '19 at 19:50

1 Answers1

-1

If you are using interface builder, you can use Unwind Segue and create a custom UIStoryboardSegue with completion block like this

class ViewController: UIViewController {
    @IBAction func unwind(_ segue: UIStoryboardSegue) {
        if let segue = segue as? StoryboardSegue {
            segue.completion = {
                // present or push in here
            }
        }
    }
}

class StoryboardSegue: UIStoryboardSegue {
    var completion: (() -> Void)?

    override func perform() {
        super.perform()
        self.destination.transitionCoordinator?.animate(alongsideTransition: { _ in

        }, completion: { _ in
             // do what you want after the animation is finished
           self.completion?()
        })
    }
}
AIex H.
  • 21
  • 3
  • That calls `didComplete` before the animation has finished. The whole problem is to do the completion _after_ the animation has finished. – matt Jan 30 '19 at 18:30
  • the idea actually would work for my purpose, too. I changed the code a little bit. Instead of popViewController, I created unwind UIStoryboardSegueWithCompletion as you suggested. and hooked the 2nd performSegue to the final VC in the completion block that comes with UIStoryboardSegueWithCompletion. I think I have two better solutions for my purpose now. Thanks. – Sean Jan 30 '19 at 19:02
  • If you want to call `didComplete` after the animation has finished. you can use `self.destination` or `self.source` 's `transitionCoordinator`to do this. You can find the example in my updated answer – AIex H. Jan 31 '19 at 11:23