1

When creating a UIViewControllerRepresentable for SwiftUI, how do you create a Coordinator so that it can access the delegate of a third party library?

In this case, I am trying to access BBMetal, a photo-filtering library.

This is a truncated version of the code we are trying to 'bridge' to SwiftUI:

class CameraPhotoFilterVC: UIViewController {
    private var camera: BBMetalCamera!
    private var metalView: BBMetalView!
    private var faceView: UIView!

    override func viewDidLoad() {
        super.viewDidLoad()
        ...

    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        camera.start()
    }...
}

extension CameraPhotoFilterVC: BBMetalCameraPhotoDelegate {
    func camera(_ camera: BBMetalCamera, didOutput texture: MTLTexture) {
        // do something with the photo
    }

    func camera(_ camera: BBMetalCamera, didFail error: Error) {
        // In main thread
        print("Fail taking photo. Error: \(error)")
    }
}

Using UIViewRepresentable everything sets up properly and the CameraPhotoFilterVC works, starts up the camera, etc, but the extension does not respond. We tried to set this up as a Coordinator:

func makeCoordinator() -> Coordinator {
 Coordinator(self)
}

func makeUIViewController(context: UIViewControllerRepresentableContext<CameraPreviewView>) -> CameraViewController {
 let cameraViewController = CameraViewController()
 // Throws an error because what we really want is a BBMetalCameraPhotoDelegate
 //cameraViewController.delegate = context.coordinator
 return cameraViewController
}

class Coordinator: NSObject, BBMetalCameraPhotoDelegate {
 var parent: CameraPreviewView
 init(_ parent: CameraPreviewView) {
  self.parent = parent
 }

 func camera(_ camera: BBMetalCamera, didOutput texture: MTLTexture) {
  print("do something with the photo")
 }
 func camera(_ camera: BBMetalCamera, didFail error: Error) {
  print("Fail taking photo. Error: \(error)")
 }
}

We also tried simply leaving an extension of the ViewController:

final class CameraViewController : UIViewController  {
...
}

extension CameraViewController: BBMetalCameraPhotoDelegate {
   func camera(_ camera: BBMetalCamera, didOutput texture: MTLTexture) {
        ...
}

However the delegate methods from BBMetalCameraPhotoDelegate do not 'fire.

I suppose the question is: in UIViewControllerRepresentable or UIViewRepresentable, how do you add an "external" delegate in the makeUIViewController method?

Usually, if this was say a UIPickerView, the following line would work:

picker.delegate = context.coordinator

But in this case the delegate is 'once removed'

dot3
  • 1,078
  • 1
  • 13
  • 21
  • 1
    Why not set `camera.delegate = self` in `viewDidLoad`? – rob mayoff Nov 27 '19 at 20:41
  • Wow thank you for your answer. It wasn't exactly the issue but it triggered a thought on what to examine. In this case, the issue is that the third party library doesn't CALL it a delegate - it's called photoDelegate. And so all of the attempts I made would return errors. By adding camera.photoDelegate = self in viewDidLoad it worked! Thank you. – dot3 Nov 27 '19 at 20:57

1 Answers1

1

You need to set the BBMetalCamera's delegate at some point before you use it.

You might do it immediately after creating it. You didn't show how you create it, so I don't know if that would be a good place to set it.

You could probably just do it in viewDidLoad:

override func viewDidLoad() {
    super.viewDidLoad()

    camera.photoDelegate = self
}
rob mayoff
  • 375,296
  • 67
  • 796
  • 848