Доступ к объекту @Environment из объекта UIViewControllerRepresentable

Я использовал этот подход для включения камеры в swiftUI:https://medium.com/@gaspard.rosay/create-a-camera-app-with-swiftui-60876fcb9118

UIViewControllerRepresentable реализуется классом PageFourView. PageFourView является одним из TabView родительского View. у меня есть@EnvironmentObjectпередается из SceneDelegate в родительское представление, а затем в PageFourView. Но когда я пытаюсь получить доступ@EnvironmentObject из метода makeUIViewController PageFourView я получаю сообщение об ошибке:

Неустранимая ошибка: не найдено ObservableObject типа Data. View.environmentObject(_:) для данных может отсутствовать как предок этого представления

... хотя я вижу объект @Environment из context.environment. Вот мой код:

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

вот родительский вид, из которого вызывается PageFourView:


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

1 ответ

А также UIViewRepresentable а также UIViewControllerRepresentable это Viewи должен быть структурой.

В описанном случае представление контроллера не требуется, потому что вы работаете с представлением, поэтому вот исправленный код:

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

кстати, тебе не нужно проходить .environmentObject для вложенных представлений в той же иерархии представлений, только для новой иерархии, например листов, поэтому вы можете использовать упрощенный код, как показано ниже

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

Обновление: дляCameraViewController просто оберните его, как показано ниже

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

    func updateUIViewController(_ uiViewController: CameraViewController, context: Context) {
    }
}
Другие вопросы по тегам