I’m working on an ARKit project in Swift where I’m trying to receive AR anchors and place a small sphere at each detected anchor in the AR scene. I have a class AppModel that conforms to ARSessionDelegate
, and it manages the AR session and scene content.
I get the following error:
Call to main actor-isolated instance method ‘createSphereEntity(radius:)’ in a synchronous nonisolated context
How to solve?
import Foundation
import RealityAR
import SwiftUI
import ARKit
import RealityKit
@MainActor
@Observable
class AppModel: NSObject, ARSessionDelegate {
let session = ARSession()
// let sceneRecostruction = SceneReconstructionProvider()
// let handTracking = HandTrackingProvider()
var arView: ARView!
var objectInScene = Entity()
override init() {
super.init()
setupARView()
}
func setupARView() {
// Initialize the ARView
arView = ARView(frame: .zero)
arView.session.delegate = self // Set ARSessionDelegate
// Create AR session configuration
let configuration = ARWorldTrackingConfiguration()
configuration.planeDetection = [.horizontal, .vertical]
// Enable scene reconstruction if needed
if ARWorldTrackingConfiguration.supportsSceneReconstruction(.mesh) {
configuration.sceneReconstruction = .mesh
}
// Run AR session
arView.session.run(configuration)
print("Session running")
}
func loadModel() async {
// Add the initial RealityKit content
if let person = try? await Entity(named: "person", in: realityARBundle) {
let radians = 180.0 * Float.pi / 180.0
person.transform.rotation = simd_quatf(angle: radians,axis: SIMD3<Float>(0,1,0))
person.scale = SIMD3(0.5, 0.5, 0.5)
person.components.set(GroundingShadowComponent(castsShadow: true))
let anchor = AnchorEntity(.plane(.horizontal, classification: .table, minimumBounds: SIMD2(0.5, 0.5)))
anchor.addChild(person)
arView.scene.addAnchor(anchor)
} else {
print("Couldn't load the character")
}
}
// Helper function to create a sphere entity
func createSphereEntity(radius: Float) -> ModelEntity {
let mesh = MeshResource.generateSphere(radius: radius)
let material = SimpleMaterial(color: .blue, isMetallic: false)
return ModelEntity(mesh: mesh, materials: [material])
}
nonisolated func session(_ session: ARSession, didAdd anchors: [ARAnchor]) {
let spere = createSphereEntity(radius: 0.1) // <------ error here
}
}
If ARSessionDelegate
methods, such as session(_:didAdd:)
, are called on the main thread, you can inform the compiler of this with assumeIsolated
, and it will do a runtime check for you:
nonisolated func session(_ session: ARSession, didAdd anchors: [ARAnchor]) {
MainActor.assumeIsolated {
let sphere = createSphereEntity(radius: 0.1)
…
}
}
The ARSession
documentation is a bit light with respect to threading, but its delegateQueue
documentation says:
If this value is
nil
(the default), the session calls your delegate methods on the main queue.
So, I suspect that this will be running on the main thread (unless you overrode the delegateQueue
somewhere). In which case, the assumeIsolated
would be the correct approach.