当ARKit按如下方式呈现场景时:
class ARSCNView: SCNView {
...
var session: ARSession
...
override var context: EAGLContext {
get
...
set {
...
}
}
...
override func render(atTime: TimeInterval) {
...
self.session.update()
...
self.pointOfView = self.session.currentFrame?.camera
.map { pointOfView(for: $0) }
super.render(atTime: atTime)
}
...
}
在 render(atTime:)
方法中调用 update()
可以导致 session
因为被多次调用而死锁,并且 SCNRenderer
中的 ARKit 自定义视图使用单独的 EAGLContext
。 ARKit 在每个 EAGLContext
上实例化了一个 ARSession
,这些 ARSession
间嵌套使用造成死锁。解决方法如下:
SCNView
子类的 update(_:)
中。Code:
class ViewController: UIViewController {
let arService = ARService()
override func viewDidLoad() {
super.viewDidLoad()
...
arService.view.frame = view.frame
view.addSubview(arService.view)
...
}
}
class ARService: NSObject, ARSessionDelegate, SCNSceneRendererDelegate {
let sceneView: SCNView
let session: ARSession
let scene: SCNScene // default anchor
init() {
sceneView = SCNView()
session = ARSession()
scene = SCNScene(named: "default.scn")!
super.init()
configureSceneView()
configureSession()
}
private func configureSceneView() {
sceneView.frame = CGRect.zero
sceneView.delegate = self
sceneView.antialiasingMode = .multisampling4X
}
private func configureSession() {
let configuration = ARWorldTrackingConfiguration()
configuration.planeDetection = .horizontal
session.run(configuration) // missing in original question
session.delegate = self
}
func renderer(_ renderer: SCNSceneRenderer, willRenderScene scene: SCNScene, atTime time: TimeInterval) {
session.update() // moved