I saw the synchronous
and asynchronous
loading from this link, but I am not understand about that. Could anyone explain the difference of them. Moreover, there is a caution:
Use RealityKit’s synchronous loading methods from the main thread only. RealityKit throws a runtime exception if you attempt to use it from any other thread. If you need to load a scene on a background thread, use asynchronous loading instead.
What is the meaning of a main thread and background thread in this context?
If you click on Experience.loadBox()
and select Jump To Definition
command from context menu, you'll see the generated Reality Composer's code. This code has both sync
and async
loading methods. If your scene contains a "lightweight" model with a "lightweight" texture, use the synchronous loadBox()
throwing method, which must be executed on the main thread.
In iOS, the main dispatch queue
is a globally available serial
queue executing tasks on the app's main thread. That means you can't run anything on that queue while the queue is busy. A serial queue can only use one thread at a time.
public static func loadBox() throws -> Experience.Box {
guard let realityFileURL = Foundation.Bundle(for: Experience.Box.self).url(
forResource: "Experience",
withExtension: "reality")
else {
throw Experience.LoadRealityFileError.fileNotFound("Experience.reality")
}
let realityFileSceneURL = realityFileURL.appendingPathComponent("Box",
isDirectory: false)
let anchorEntity = try Experience.Box.loadAnchor(contentsOf: realityFileSceneURL)
return createBox(from: anchorEntity)
}
However, when RealityKit scene contains a model consisting of a large number of polygons with 4K textures, use the loadBoxAsync()
method, which must be concurrently executed on several background threads, to prevent ARView from freezing (i.e. not for executing a loading on the main thread).
public static func loadBoxAsync(completion: @escaping (Swift.Result<Experience.Box, Swift.Error>) -> Void) {
guard let realityFileURL = Foundation.Bundle(for: Experience.Box.self).url(
forResource: "Experience",
withExtension: "reality")
else {
completion(.failure(Experience.LoadRealityFileError.fileNotFound("Experience.reality")))
return
}
var cancellable: Combine.AnyCancellable?
let realityFileSceneURL = realityFileURL.appendingPathComponent("Box",
isDirectory: false)
let loadRequest = Experience.Box.loadAnchorAsync(contentsOf: realityFileSceneURL)
cancellable = loadRequest.sink(receiveCompletion: { loadCompletion in
if case let .failure(error) = loadCompletion {
completion(.failure(error))
}
streams.removeAll { $0 === cancellable }
}, receiveValue: { entity in
completion(.success(Experience.createBox(from: entity)))
})
cancellable?.store(in: &streams)
}