在 SwiftUI 中从 UIViewController 调用函数 [英] Calling functions from UIViewController in SwiftUI

查看:37
本文介绍了在 SwiftUI 中从 UIViewController 调用函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm looking to call a function inside a UIKit UIViewController from a button managed by Swift UI

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

In my Swift UI View I have:

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

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

which I see creates two instances, one directly created just like calling any class, and the other created by the required makeUIViewController method needed for Swift UI to manage UIKit UIViewControllers.

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

However when I attached a function to a button in my Swift UI say, cameraViewController.takePhoto() The instance that is referenced is not the one displayed.

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

How can I obtain the specific instance that is displayed?

推荐答案

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

There are probably multiple solutions to this problem, but one way or another, you'll need to find a way to keep a reference to or communicate with the UIViewController. Because SwiftUI views themselves are pretty transient, you can't just store a reference in the view itself, because it could get recreated at any time.

要使用的工具:

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

  • ObservableObject -- this will let you store data in a class instead of a struct and will make it easier to store references, connect data, etc

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

Coordinator -- in a UIViewRepresentable, you can use a Coordinator pattern which will allow you to store references to the UIViewController and communicate with it

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

Combine Publishers -- these are totally optional, but I've chosen to use them here since they're an easy way to move data around without too much boilerplate code.

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

这里发生了什么:

  1. VCLink 是一个 ObservableObject,我用它作为中间人在视图之间进行通信
  2. ContentView 引用了 VCLink -- 当按钮被按下时,VCLink 上的 Publisher> 将其传达给任何订阅者
  3. 当创建/更新 VCRepresented 时,我在其 Coordinator
  4. 中存储对 ViewController 和 VCLink 的引用
  5. Coordinator 接受 Publisher 并在其 sink 方法中对存储的 ViewController 执行操作.在这个演示中,我只是打印动作.在您的示例中,您希望触发照片本身.
  1. VCLink is an ObservableObject that I'm using as a go-between to communicate between views
  2. The ContentView has a reference to the VCLink -- when the button is pressed, the Publisher on VCLink communicates that to any subscribers
  3. When the VCRepresented is created/updated, I store a reference to the ViewController and the VCLink in its Coordinator
  4. The Coordinator takes the Publisher and in its sink method, performs an action on the stored ViewController. In this demo, I'm just printing the action. In your example, you'd want to trigger the photo itself.

这篇关于在 SwiftUI 中从 UIViewController 调用函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆