从SwiftUI视图切换到UIViewController

13

我正在努力将一些SwiftUI内容实现到我的现有应用程序中。我目前有一个UIViewController,其中包含一个MTKView用于摄像头预览。

我已经创建了一个新的SwiftUI视图,它现在是我的视图,如在我的SceneDelegate.swift文件中设置的那样。SwiftUI视图在启动时加载,就像预期的那样。现在,我想创建一个segue,在该segue中,当用户轻击列表中的一行时,它将全屏幕切换到我的现有UIViewController。以下是我的代码调用方式;

var body: some View {
    VStack {
        NavigationView {
            List(sessionTypes) { session in
                NavigationLink(destination: CameraControllerWrapper()) {
                    SessionRow(session: session)
                    .frame(height: 40.0)
                }
            }
        .navigationBarTitle(Text("Camera Types"))
        }
    }
}

为了后代,这里是我的CameraControllerWrapper UIViewControllerRepresentable;

struct CameraControllerWrapper: UIViewControllerRepresentable {
typealias UIViewControllerType = CameraController

   func makeUIViewController(context: UIViewControllerRepresentableContext<CameraControllerWrapper>) -> CameraControllerWrapper.UIViewControllerType {
    return CameraController()
   }

   func updateUIViewController(_ uiViewController: CameraControllerWrapper.UIViewControllerType, context: UIViewControllerRepresentableContext<CameraControllerWrapper>) {
    //
   }
}

虽然这个“方法”可以工作,但是一旦调用CameraController,我的应用程序就会崩溃,因为似乎找不到任何IBOutlets。 CameraController是在故事板中构建的UIViewController。


为了澄清,您是说您有(1)一个Storyboard应用程序,您将(2)MainViewController根视图设置为SwiftUI视图,并在此根视图中放置了(3)NavigationView并且(4)导航到一个具有(5)定义了IBOutletsUIViewControllerRepresentable?如果这个链条中的某些内容有误,请纠正我。 - user7014451
我认为这是正确的。我有一个UIViewController,它是在Storyboard中构建和设计的,具有IBOutlets,并且以前是我的入口视图控制器。现在我添加了一个SwiftUI视图作为我的根视图,并希望转换到以前的UIViewController,它现在是一个“第二”视图控制器,不再是主要的。 - ZbadhabitZ
2个回答

13
我成功解决了这个问题,意识到我需要从“Storyboard”中实例化UIViewController,而不是在代码中实例化(因为我已经在“Storyboard”中构建了其布局,同时还有一些编程元素)。 为了使用上述的NavigationLink,我需要调整我的UIViewControllerRepresentable如下;
struct CameraControllerWrapper: UIViewControllerRepresentable {
    typealias UIViewControllerType = CameraController

    func makeUIViewController(context: UIViewControllerRepresentableContext<CameraControllerWrapper>) -> CameraControllerWrapper.UIViewControllerType {

    let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
    let mainViewController: CameraController = mainStoryboard.instantiateViewController(withIdentifier: "CameraController") as! CameraController
      return mainViewController

    }

    func updateUIViewController(_ uiViewController: CameraControllerWrapper.UIViewControllerType, context: UIViewControllerRepresentableContext<CameraControllerWrapper>) {
        //
    }
}

0
对于那些可能相对较新于Swift的人,@ZbadhabitZ的答案有一些潜在的优化方法,以下是一个简短的例子。
extension NotesVC : UIViewControllerRepresentable {

    func makeUIViewController(context: Context) -> NotesVC {
        let storyboard =  UIStoryboard(name: "Main", bundle: nil)
        let vc = storyboard.instantiateViewController(withIdentifier: "NotesVC") 
        return vc as! NotesVC
    }

    func updateUIViewController(_ vc: NotesVC, context: Context) {
        // your stuff here
    }
}

考虑将Swift协议作为扩展添加。这样可以更整洁和灵活(包括通过在完全不同的文件中定义协议扩展来将类适应于协议)。例如,我最近尝试了一个第三方选项卡控制器,需要将我的类适应一个协议,并且指令涉及编辑多个文件,包括添加的和自己的文件,而我能够将其中80%放入单独的文件中作为扩展,而不必在尝试新功能时弄乱我的代码,而且在完成后很容易删除。
  • 过于繁琐的函数参数类型定义是不必要的,甚至会让人感到困惑。

    Apple Developer demo 展示了一个使用 PageViewController 的示例,证明所有额外的类型定义都是不必要的:


  • 原回答的代码没有使用 Swift 的隐式类型。例如,可以将以下代码:
    ``` let flag : Bool = false ``` 改写为 ```let flag = false```
    在该声明中,`flag` 将隐式地被定义为 `Bool` 类型。这是因为 `false` 总是意味着 `Bool` 类型。就像默认情况下 `1.0` 总是意味着 `Double` 类型等等。当你开始涉及更长的类名时,收益甚至更大。

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接