Search code examples
swiftrealitykitreality-composer

What's the difference between sync / async loading of Reality Composer files?


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?


Solution

  • Sync and async loading methods

    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)
    }