在 SwiftUI 中从 UIViewController 调用函数

Posted

技术标签:

【中文标题】在 SwiftUI 中从 UIViewController 调用函数【英文标题】:Calling functions from UIViewController in SwiftUI 【发布时间】:2021-01-27 16:52:50 【问题描述】:

我希望通过 Swift UI 管理的按钮调用 UIKit UIViewController 中的函数

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

struct CameraView: View 
        var body: some View 
            cameraViewController = CameraViewController()
...

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

但是,当我在 Swift UI 中将函数附加到按钮时,cameraViewController.takePhoto() 引用的实例不是显示的实例。

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

【问题讨论】:

【参考方案1】:

这个问题可能有多种解决方案,但无论哪种方式,您都需要找到一种方法来保持对UIViewController 的引用或与之通信。因为 SwiftUI 视图本身是非常短暂的,所以您不能只在视图本身中存储一个引用,因为它可以随时重新创建。

使用工具:

ObservableObject -- 这将使您可以将数据存储在 class 而不是结构中,并且可以更轻松地存储引用、连接数据等

协调器 -- 在 UIViewRepresentable 中,您可以使用协调器模式,它允许您存储对 UIViewController 的引用并与之通信

Combine Publishers -- 这些是完全可选的,但我在这里选择使用它们,因为它们是一种无需太多样板代码即可轻松移动数据的方法。

import SwiftUI
import Combine

struct ContentView: View 
    @ObservedObject 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
    

这里发生了什么:

    VCLink 是一个 ObservableObject,我用作在视图之间进行通信的中间人 ContentView 具有对 VCLink 的引用——当按下按钮时,VCLink 上的 Publisher 会将其传达给任何订阅者 当VCRepresented 被创建/更新时,我在它的Coordinator 中存储了对ViewController 和VCLink 的引用 Coordinator 采用Publisher 并在其sink 方法中对存储的ViewController 执行操作。在这个演示中,我只是打印动作。在您的示例中,您希望触发照片本身。

【讨论】:

以上是关于在 SwiftUI 中从 UIViewController 调用函数的主要内容,如果未能解决你的问题,请参考以下文章

在 SwiftUI 中从数据模型中搜索数组

如何在 SwiftUI 中从 FetchedResults (CoreData) 中获取 NSOrderedSet

如何在 SwiftUI 中从减去的子视图中关闭视图

在 SwiftUI 中从 Observable 视图模型初始化 Map

无法在 SwiftUI 按钮视图中从 Cloud Firestore 获取数据

如何在 SwiftUI 中从通知深层链接到屏幕?