4

I used this approach to incorporate camera with swiftUI: https://medium.com/@gaspard.rosay/create-a-camera-app-with-swiftui-60876fcb9118

The UIViewControllerRepresentable is implemented by PageFourView class. PageFourView is one of the TabView of the parental View. I have an @EnvironmentObject passed from the SceneDelegate to the parent view and then to PageFourView. But when I am trying to acess @EnvironmentObject from makeUIViewController method of PageFourView I get an error:

Fatal error: No ObservableObject of type Data found. A View.environmentObject(_:) for Data may be missing as an ancestor of this view

... even though I can see the @Environment object from context.environment. Here is my code:

import UIKit
import SwiftUI
import Combine


final class PageFourView: UIViewController, UIViewControllerRepresentable {
    
    public typealias UIViewControllerType = PageFourView
    
    @EnvironmentObject var data: Data
    
    var previewView: UIView!
    
    override func viewDidLoad() {
        
        previewView = UIView(frame: CGRect(x:0, y:0, width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height))
        
        previewView.contentMode = UIView.ContentMode.scaleAspectFit
        view.addSubview(previewView)
        
    }
    
    func makeUIViewController(context: UIViewControllerRepresentableContext<PageFourView>) -> PageFourView {
        print(context.environment)
        print(self.data.Name)
        return PageFourView()
    }

    func updateUIViewController(_ uiViewController: PageFourView, context: UIViewControllerRepresentableContext<PageFourView>) {
    }
}

struct PageFourView_Previews: PreviewProvider {
    @State static var data = Data()
    static var previews: some View {
        PageFourView().environmentObject(self.data)
    }
}

here is the parental view that PageFourView is called from:


import SwiftUI

struct AppView: View {
    
    @EnvironmentObject var data: Data
    
    var body: some View {
        TabView {
            PageOneView().environmentObject(data)
                .tabItem {
                    Text("PageOne")
                }

            PageTwoView().environmentObject(data)
                .tabItem {
                    Text("PageTwo")
                }
            PageThreeView().environmentObject(data)
            .tabItem {
                Text("PageThree")
            }
            PageFourView().environmentObject(data)
            .tabItem {
                Text("PageFour")
            }
            
            
        }
    }
}

struct AppView_Previews: PreviewProvider {
    
    @State static var data = Data()
    static var previews: some View {
        AppView().environmentObject(self.data)
    }
}
final class CameraViewController: UIViewController {
    let cameraController = CameraController()
    var previewView: UIView!

    override func viewDidLoad() {

        previewView = UIView(frame: CGRect(x:0, y:0, width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height))
        previewView.contentMode = UIView.ContentMode.scaleAspectFit
        view.addSubview(previewView)

        cameraController.prepare {(error) in
            if let error = error {
                print(error)
            }

            try? self.cameraController.displayPreview(on: self.previewView)
        }

    }
}


extension CameraViewController : UIViewControllerRepresentable{
    public typealias UIViewControllerType = CameraViewController

    public func makeUIViewController(context: UIViewControllerRepresentableContext<CameraViewController>) -> CameraViewController {
        return CameraViewController()
    }

    public func updateUIViewController(_ uiViewController: CameraViewController, context: UIViewControllerRepresentableContext<CameraViewController>) {
    }
}
3
  • Can you share the view, where you are using PageFourView? Commented Jul 9, 2020 at 21:50
  • 1
    Just edited my post by adding the parental view. Commented Jul 9, 2020 at 22:13
  • I reproduced the issue.. actually @EnvironmentObject should be available in ViewRepresentable and should work. However, still crashing for me either Commented Jul 9, 2020 at 22:44

1 Answer 1

3

And UIViewRepresentable and UIViewControllerRepresentable is-a View and must be a struct.

In described case controller representable is not needed, because you operate with view, so here is corrected code:

struct PageFourView: UIViewRepresentable {
    @EnvironmentObject var data: Data

    func makeUIView(context: Context) -> UIView {
        let view = UIView(frame: CGRect(x:0, y:0, width: UIScreen.main.bounds.size.width, 
                          height: UIScreen.main.bounds.size.height))
        view.contentMode = UIView.ContentMode.scaleAspectFit

        print(context.environment)
        print(self.data.Name)
        return view
    }

    func updateUIView(_ uiView: UIView, context: Context) {
    }
}

btw, you don't need to pass .environmentObject to subviews in same view hierarchy, only for new hierarchy, like sheets, so you can use simplified code as below

var body: some View {
    TabView {
        PageOneView()
            .tabItem {
                Text("PageOne")
            }
        PageTwoView()
            .tabItem {
                Text("PageTwo")
            }
        PageThreeView()
        .tabItem {
            Text("PageThree")
        }
        PageFourView()
        .tabItem {
            Text("PageFour")
        }
    }
}

Update: for CameraViewController just wrap it as below

struct CameraView: UIViewControllerRepresentable {
    func makeUIViewController(context: Context) -> CameraViewController {
        CameraViewController()
    }

    func updateUIViewController(_ uiViewController: CameraViewController, context: Context) {
    }
}
Sign up to request clarification or add additional context in comments.

3 Comments

Great job.. I tried that several times yesterday I just didn’t noticed it is declared as class..
Asperi, thank you for your solution. But the problem is that I am trying to implement camera in swiftUI, and approach I found is this one: medium.com/@gaspard.rosay/… (I posted link in my original post). And here is the implementation github.com/RosayGaspard/SwiftUI-Simple-camera-app/commit/… I hope that their CameraViewController could be rewritten at struct.
Asperi, I mean camera implementation that I am trying to use seems to require that UIViewControllerRepresentative is a class, because of the methods it needs to access camera. the implementation is given here: github.com/RosayGaspard/SwiftUI-Simple-camera-app/commit/… I updated my original post with their implementation of UIViewControllerRepresentative from the above link.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.