在 SwiftUI 中从 UIViewController 调用函数

etn*_*008 5 uikit swiftui

我希望从 Swift UI 管理的按钮调用 UIKit UIViewController 内的函数

在我的 Swift UI 视图中,我有:

struct CameraView: View {
        var body: some View {
            cameraViewController = CameraViewController()
...
Run Code Online (Sandbox Code Playgroud)

我看到它创建了两个实例,一个像调用任何类一样直接创建,另一个由makeUIViewControllerSwift UI 管理 UIKit UIViewControllers 所需的方法创建。

然而,当我将一个函数附加到 Swift UI 中的按钮时,会说,cameraViewController.takePhoto()引用的实例不是显示的实例。

如何获取显示的具体实例?

jn_*_*pdx 8

此问题可能有多种解决方案,但无论如何,您需要找到一种方法来保留对UIViewController. 因为 SwiftUI 视图本身非常短暂,所以您不能只在视图本身中存储引用,因为它可以随时重新创建。

使用工具:

  • ObservableObject——这将允许您将数据存储在而不是结构中,并且使存储引用、连接数据等变得更容易

  • 协调器 - 在 a 中UIViewRepresentable,您可以使用协调器模式,该模式允许您存储对 的引用UIViewController并与其进行通信

  • 组合发布者——这些是完全可选的,但我选择在这里使用它们,因为它们是一种无需太多样板代码即可移动数据的简单方法。

import SwiftUI
import Combine

struct ContentView: View {
    @StateObject var vcLink = VCLink()
    var body: some View {
        VStack {
            VCRepresented(vcLink: vcLink)
            Button("Take photo") {
                vcLink.takePhoto()
            }
        }
    }
}

enum LinkAction {
    case takePhoto
}

class VCLink : ObservableObject {
    @Published var action : LinkAction?
    
    func takePhoto() {
        action = .takePhoto
    }
}

class CustomVC : UIViewController {
    func action(_ action : LinkAction) {
        print("\(action)")
    }
}

struct VCRepresented : UIViewControllerRepresentable {
    var vcLink : VCLink
    
    class Coordinator {
        var vcLink : VCLink? {
            didSet {
                cancelable = vcLink?.$action.sink(receiveValue: { (action) in
                    guard let action = action else {
                        return
                    }
                    self.viewController?.action(action)
                })
            }
        }
        var viewController : CustomVC?
        
        private var cancelable : AnyCancellable?
    }
    
    func makeCoordinator() -> Coordinator {
        return Coordinator()
    }
    
    func makeUIViewController(context: Context) -> CustomVC {
        return CustomVC()
    }
    
    func updateUIViewController(_ uiViewController: CustomVC, context: Context) {
        context.coordinator.viewController = uiViewController
        context.coordinator.vcLink = vcLink
    }
}
Run Code Online (Sandbox Code Playgroud)

这里发生了什么:

  1. VCLinkObservableObject我用来作为观点之间沟通的中间人
  2. TheContentView引用了VCLink-- 当按下按钮时,PublisheronVCLink会将其传达给任何订阅者
  3. 创建/更新时VCRepresented,我存储对 ViewController 的引用并在VCLink其中Coordinator
  4. 接受CoordinatorPublisher在其sink方法中对存储的 执行操作ViewController。在这个演示中,我只是打印动作。在您的示例中,您想要触发照片本身。