Search code examples
scenekitpresentmodalviewcontrollerios11xcode9-betaarkit

EXC_BREAKPOINT when trying to present modally from storyboard in completion handler


In my ViewController.swift I have this method which presents a viewcontroller modally after the animations for the boxes are completed:

@objc func sceneTapped(recognizer: UITapGestureRecognizer) {
    let location = recognizer.location(in: sceneView)

    let hitResults = sceneView.hitTest(location, options: nil)

    if hitResults.count > 0 {
        let result = hitResults[0]
        let box = result.node

        let fadeAction = SCNAction.fadeOut(duration: 1.0)
        let rotateAction =  SCNAction.rotate(by: CGFloat(Double.pi*2), around: SCNVector3(x: 0.5, y: 1.5, z: 0), duration: 1.0)
        let groupActions = SCNAction.group([rotateAction, fadeAction])

        if box.name == Present.left.rawValue || box.name == Present.middle.rawValue || box.name == Present.right.rawValue {
            box.runAction(groupActions, completionHandler: presentWebView)
        }

    }

}

presentWebView uses the storyboard to instantiate the viewcontroller:

func presentWebView(){
        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        let vc = storyboard.instantiateViewController(withIdentifier: "webViewController")
        self.present(vc, animated: true, completion: nil)
    }

But every time the app crashes on self.present(vc, animated: true, completion: nil) with EXC_BREAKPOINT (code=1, subcode=0x1a1579b50)

HOWEVER, when I don't present the view controller in the completion hander, i.e.:

@objc func sceneTapped(recognizer: UITapGestureRecognizer) {
    presentWebView()
}

This works completely fine

So I don't understand why presenting a view controller in a completion handler causes a crash.

Any help would be greatly appreciated!


Solution

  • the SCNAction completion handler will not be called in the main thread.

    Per UIKit guidelines your UI code needs to run on the main thread. You should be able to do that using DispatchQueue.main.async { ... }