BUG IN CLIENT OF LIBDISPATCH error in Swift Playgrounds app

import UIKit
import SceneKit
import ARKit
import PlaygroundSupport

class ViewController: UIViewController, ARSCNViewDelegate {
    //Declaring what we may need
    let configuration = ARWorldTrackingConfiguration()
    let sceneView: ARSCNView = ARSCNView(frame: CGRect(x: 0, y: 0, width: 300, height: 600))
    var drawBtn: UIButton {
        let sampleBtn = UIButton(frame: CGRect(x: 170, y: 550, width: 100, height: 50))
        sampleBtn.setTitle("Draw", for: .normal)
        sampleBtn.setTitleColor(UIColor.black, for: .normal)
        sampleBtn.backgroundColor = UIColor.white
        return sampleBtn
    }
    //setting up our objects
    override func viewDidLoad(){
        super.viewDidLoad()
        //setting up the scene view
        self.sceneView.debugOptions = [ARSCNDebugOptions.showFeaturePoints, ARSCNDebugOptions.showWorldOrigin]
        self.sceneView.delegate = self
        self.sceneView.showsStatistics = true
        self.sceneView.session.run(configuration)
        //adding our views as a subview to the main view
        self.view.addSubview(sceneView)
        self.view.addSubview(drawBtn)
    }
    //the renderer function
    func renderer(_ renderer: SCNSceneRenderer, willRenderScene scene: SCNScene, atTime time: TimeInterval) {
        guard let pointOfView = sceneView.pointOfView else { return }
        let transform = pointOfView.transform
        let orientation = SCNVector3(-transform.m31, -transform.m32, -transform.m33)
        let location = SCNVector3(transform.m41, transform.m42, transform.m43)
        let currentPositionOfCamera = orientation + location
        DispatchQueue.main.async {
            if self.drawBtn.isHighlighted {
                let sphereNode = SCNNode(geometry: SCNSphere(radius: 0.02))
                sphereNode.position = currentPositionOfCamera
                self.sceneView.scene.rootNode.addChildNode(sphereNode)
                sphereNode.geometry?.firstMaterial?.diffuse.contents = UIColor.red
                //print("draw button is being pressed")
            }
            else {
                let pointer = SCNNode()
                pointer.geometry = SCNSphere(radius: 0.01)
                pointer.name = "pointer"
                pointer.position = currentPositionOfCamera
               
                self.sceneView.scene.rootNode.enumerateChildNodes({ (myNode, _) in
                    if myNode.name == "pointer" {
                        myNode.removeFromParentNode()
                    }
                })
                self.sceneView.scene.rootNode.addChildNode(pointer)
                pointer.geometry?.firstMaterial?.diffuse.contents = UIColor.red
            }
        }
    }
}

//Modifying the + so that it can add two SCNVector3
func +(left: SCNVector3, right: SCNVector3) -> SCNVector3 {
    return SCNVector3Make(left.x + right.x, left.y + right.y, left.z + right.z)
}

let vc = ViewController()
vc.preferredContentSize = CGSize(width: 1080, height: 1920)
PlaygroundPage.current.liveView = vc
PlaygroundPage.current.needsIndefiniteExecution = true

Hey there! I am running the code above on my iPad in the swift playgrounds app. However once I run this, it says: "There was a problem encountered while running this playground. Check your code for mistakes". On stepping through my code, on line 30, it says - "BUG IN CLIENT OF LIBDISPATCH: dispatch_sync called on queue already owned by current thread". What may be the error and how to fix it? Please also suggest me some ways to prevent these errors in future.

Replies

Debugging problems like this is tricky in a playground because you can’t use the debugger. I recommend that you take this code and put it into a tiny iOS test app and see if that reproduces the problem. If it does, you can use the debugger to investigate the cause. If it doesn’t, you may be hitting a playground limitation [1].

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

[1] The playground tries to snapshot your view at every execution steps. If one of those execution steps is run on a secondary thread — and I’m presuming that the case here with your

renderer(_:willRenderScene:atTime:)
function — you end up trying to snapshot the view on a secondary thread, which doesn’t end well (r. 46579594).