swiftswiftuiarkitcoordinator-pattern

Pass ARView to Coordinator in Swift


I'm trying to pass ARView from MakeUIView to makeCoordinator. I need this to use ARView inside of @objc func handleTap.

struct ARViewContainer: UIViewRepresentable{
func makeUIView(context: Context) -> ARView {
        
        let myARView = ARView(frame: .zero)
        //...config and things….
        let tapGesture = UITapGestureRecognizer(target: context.coordinator, action: #selector(context.coordinator.handleTap(_:)))
        myARView.addGestureRecognizer(tapGesture)
        return myARView
        
    }
func makeCoordinator() -> Coordinator {
        Coordinator("whatshouldiusehere", self.$focusObject, self.$focusName)
    }
    class Coordinator: NSObject {
            private let view: ARView
        private var object: Binding<Entity?>
    private var objectname: Binding<String?>
        init(_ view: ARView, _ obj: Binding<Entity?>, _ objname: Binding<String?>) {
            self.objectname = objname
                self.object = obj
                self.view = view
                super.init()
            }
        @objc func handleTap(_ sender: UIGestureRecognizer? = nil) {
            guard let touchInView = sender?.location(in: view) else {
              return
            }
            guard let hitEntity = view.entity(at: touchInView) else {return}
            //doing something with object here, assigning to @Binding for example

        }
    }
}

I can't move myARView = ARView(frame: .zero) outside of makeUIView, because I'm using SwiftUI and it inits every time when variables changes.

But how I can pass it in any way?

Or is there any other option to access Binding with ARView same time?


Solution

  • A coordinator is available via context, so you can inject it via property, like

    struct ARViewContainer: UIViewRepresentable{
    func makeUIView(context: Context) -> ARView {
            
            let myARView = ARView(frame: .zero)
            //...config and things….
            let tapGesture = UITapGestureRecognizer(target: context.coordinator, action: #selector(context.coordinator.handleTap(_:)))
            myARView.addGestureRecognizer(tapGesture)
           
            context.coordinator.view = myARView     // << inject here !!
    
            return myARView
            
        }
    func makeCoordinator() -> Coordinator {
            Coordinator(self.$focusObject, self.$focusName)
        }
        class Coordinator: NSObject {
                var view: ARView?        // << optional initially
    
            private var object: Binding<Entity?>
            private var objectname: Binding<String?>
            
            init(_ obj: Binding<Entity?>, _ objname: Binding<String?>) {
                    self.objectname = objname
                    self.object = obj
                    super.init()
                }
    
        // ... other code update accordingly
    }