3

This code works:

let entity = try! Entity.load(named: "toy_robot_vintage")
anchorEntity.addChild(entity)

But this doesn't:

_ = Entity.loadAsync(named: "toy_robot_vintage")
        .sink(receiveCompletion: { loadCompletion in
            print("This is never executed")
        }, receiveValue: { entity in
            print("This is never executed")
            anchorEntity.addChild(entity)
        })

What could be the issue?

Andy Jazz
  • 49,178
  • 17
  • 136
  • 220
Isaak
  • 1,107
  • 2
  • 11
  • 29

1 Answers1

8

Use the following macOS code version to find out how to load model asynchronously:

import AppKit
import RealityKit
import Combine

class GameViewController: NSViewController {
    
    @IBOutlet var arView: ARView!
    var model: ModelEntity? = nil
    let anchor = AnchorEntity()
    var cancellable: AnyCancellable? = nil
    
    override func awakeFromNib() {
    
        arView.environment.background = .color(.systemTeal)
                
        cancellable = Entity.loadModelAsync(named: "Glasses.usdz")
            .sink(receiveCompletion: { completion in
                if case let .failure(error) = completion {
                    print("Unable to load a model due to error \(error)")
                }
                self.cancellable?.cancel()
                
            }, receiveValue: { [self] (model: Entity) in
                if let model = model as? ModelEntity {
                    self.model = model
                    cancellable?.cancel()
                    print("Congrats! Model is successfully loaded!")
                    anchor.addChild(model)
                    anchor.position = [0.4, 1.5, -1]
                    anchor.scale = [300, 300, 300]   // set appropriate scale
                    arView.scene.anchors.append(anchor)
                }
            })
    }
}

enter image description here

Andy Jazz
  • 49,178
  • 17
  • 136
  • 220
  • 1
    This works. Thank you very much. Apparently its necessary to cancel the AnyCancellable thats returned from loadModelAsync() inside the closures of loadModelAsync(). – Isaak Jul 07 '20 at 09:06
  • 3
    It's not about canceling the AnyCancellable, it's about saving a reference to the LoadRequest so the ARC won't kick it out of memory because of zero reference count. I would also suggest making the AnyCancellable weak in order to avoid cyclic reference( GameViewController -> closure -> AnyCancellable) – Nativ Apr 08 '21 at 15:06
  • 1
    If the `AnyCancellable` is weak then it will be immediately deallocated unless something else is also holding a reference to it. – Steve Madsen Feb 19 '22 at 17:49
  • This works on iOS 16 too? – user3069232 Nov 29 '22 at 07:02