复杂UIKit+;通过UIViewControllerRepresentable的SwiftUI界面

复杂UIKit+;通过UIViewControllerRepresentable的SwiftUI界面,swift,swiftui,uikit,Swift,Swiftui,Uikit,我正在构建一个摄像头应用程序,其中SwiftUI(父级)中的所有UI都包含一个包含所有录制功能的UIKit控制器。UI相当复杂,因此如果可能的话,我们希望在项目中保持这种结构 UIKit类有一些函数,如startRecord()stopRecord(),我希望从SwiftUI视图触发这些函数。因此,我想从SwiftUI视图中“调用”UIKit函数 我正在试验UIViewControllerRepresentable,能够对全局变量更改执行更新,但仍然无法从SwiftUI父级调用要触发的单个函数

我正在构建一个摄像头应用程序,其中SwiftUI(父级)中的所有UI都包含一个包含所有录制功能的UIKit控制器。UI相当复杂,因此如果可能的话,我们希望在项目中保持这种结构

UIKit类有一些函数,如startRecord()stopRecord(),我希望从SwiftUI视图触发这些函数。因此,我想从SwiftUI视图中“调用”UIKit函数

我正在试验UIViewControllerRepresentable,能够对全局变量更改执行更新,但仍然无法从SwiftUI父级调用要触发的单个函数

这里是SwiftUI文件:

init(metalView: MetalViewController?) {
    self.metalView = MetalViewController(appStatus: appStatus)
}

var body: some View {
    
    ZStack {
        
        // - Camera view
        metalView
            .edgesIgnoringSafeArea(.top)
            .padding(.bottom, 54)
        
        VStack {
            
            
            LateralMenuView(appStatus: appStatus, filterTooltipShowing: $_filterTooltipShowing)
            
            Button("RECORD", action: {
                print("record button pressed")
                metalView?.myMetalDelegate.switchRecording(). // <-- Not sure about this
            })

我喜欢使用Combine将消息通过ObserveObject传递到UIKit视图。这样,我就可以强制地给他们打电话了。我没有试图解析您的代码,而是举了一个关于这个概念的小例子:

import SwiftUI
import Combine

enum MessageBridgeMessage {
    case myMessage(parameter: Int)
}

class MessageBridge : ObservableObject {
    @Published var result = 0
    
    var messagePassthrough = PassthroughSubject<MessageBridgeMessage, Never>()
}

struct ContentView : View {
    @StateObject private var messageBridge = MessageBridge()
    
    var body: some View {
        VStack {
            Text("Result: \(messageBridge.result)")
            Button("Add 2") {
                messageBridge.messagePassthrough.send(.myMessage(parameter: messageBridge.result))
            }
            VCRepresented(messageBridge: messageBridge)
        }
    }
}

struct VCRepresented : UIViewControllerRepresentable {
    var messageBridge : MessageBridge
    
    func makeUIViewController(context: Context) -> CustomVC {
        let vc = CustomVC()
        context.coordinator.connect(vc: vc, bridge: messageBridge)
        return vc
    }
    
    func updateUIViewController(_ uiViewController: CustomVC, context: Context) {
        
    }
    
    func makeCoordinator() -> Coordinator {
        return Coordinator()
    }
    
    class Coordinator {
        private var cancellable : AnyCancellable?
        
        func connect(vc: CustomVC, bridge: MessageBridge) {
            cancellable = bridge.messagePassthrough.sink(receiveValue: { (message) in
                switch message {
                case .myMessage(let parameter):
                    bridge.result = vc.addTwo(input: parameter)
                }
            })
        }
    }
}

class CustomVC : UIViewController {
    func addTwo(input: Int) -> Int {
        return input + 2
    }
}
导入快捷界面
进口联合收割机
枚举消息桥消息{
案例myMessage(参数:Int)
}
类MessageBridge:ObservableObject{
@已发布的var结果=0
var messagePassthrough=PassthroughSubject()
}
结构ContentView:View{
@StateObject私有变量messageBridge=messageBridge()
var body:一些观点{
VStack{
文本(“结果:\(messageBridge.Result)”)
按钮(“添加2”){
messageBridge.messagePassthrough.send(.myMessage(参数:messageBridge.result))
}
VCR(messageBridge:messageBridge)
}
}
}
结构VCRepresented:UIViewControllerRepresentable{
var messageBridge:messageBridge
func makeUIViewController(上下文:context)->CustomVC{
设vc=CustomVC()
context.coordinator.connect(vc:vc,bridge:messageBridge)
返回vc
}
func updateUIViewController(uUIViewController:CustomVC,上下文:上下文){
}
func makeCoordinator()->Coordinator{
返回协调员()
}
班级协调员{
私有var可取消:任何可取消?
func connect(vc:CustomVC,桥接器:MessageBridge){
cancelable=bridge.messagePassthrough.sink(receiveValue:{(message)in
开关信息{
case.myMessage(let参数):
bridge.result=vc.addTwo(输入:参数)
}
})
}
}
}
类CustomVC:UIViewController{
func addTwo(输入:Int)->Int{
返回输入+2
}
}
在本例中,
MessageBridge
有一个
PassthroughSubject
,可以从UIKit视图(或者在本例中是UIViewController)订阅它。它属于
ContentView
,并通过参数传递给
vcsresented

VCR
中,协调器上有一个订阅发布者(
messagePassthrough
)并对消息执行操作的方法。您可以通过枚举上的关联属性(
MessageBridgeMessage
)传递参数。如果需要返回值,可以将其存储在
MessageBridge
上的@Published属性上(或者,您可以设置另一个发布服务器,使其反向运行)


这有点冗长,但似乎是一种非常可靠的模式,可以与您需要的任何级别的树(SwiftUI视图、可表示视图、UIKit视图等)进行通信。

令人印象深刻。如何用协议来代替呢?context.coordinator.connect是我所缺少的吗?SwiftUI和Combine由于依赖于属性包装器,往往不能很好地使用协议。但是你当然可以尝试一下,看看你能抽象出什么。
class MetalController: UIViewController {

var _mydelegate: MetalViewControllerDelegate?
...
override func viewDidLoad() {
 ...
    self._mydelegate = self
}

extension MetalController: MetalViewControllerDelegate {
    func switchRecording() {
        print("THIS SHOULD BE WORKING, BUT ITS NOT")
    }
}
import SwiftUI
import Combine

enum MessageBridgeMessage {
    case myMessage(parameter: Int)
}

class MessageBridge : ObservableObject {
    @Published var result = 0
    
    var messagePassthrough = PassthroughSubject<MessageBridgeMessage, Never>()
}

struct ContentView : View {
    @StateObject private var messageBridge = MessageBridge()
    
    var body: some View {
        VStack {
            Text("Result: \(messageBridge.result)")
            Button("Add 2") {
                messageBridge.messagePassthrough.send(.myMessage(parameter: messageBridge.result))
            }
            VCRepresented(messageBridge: messageBridge)
        }
    }
}

struct VCRepresented : UIViewControllerRepresentable {
    var messageBridge : MessageBridge
    
    func makeUIViewController(context: Context) -> CustomVC {
        let vc = CustomVC()
        context.coordinator.connect(vc: vc, bridge: messageBridge)
        return vc
    }
    
    func updateUIViewController(_ uiViewController: CustomVC, context: Context) {
        
    }
    
    func makeCoordinator() -> Coordinator {
        return Coordinator()
    }
    
    class Coordinator {
        private var cancellable : AnyCancellable?
        
        func connect(vc: CustomVC, bridge: MessageBridge) {
            cancellable = bridge.messagePassthrough.sink(receiveValue: { (message) in
                switch message {
                case .myMessage(let parameter):
                    bridge.result = vc.addTwo(input: parameter)
                }
            })
        }
    }
}

class CustomVC : UIViewController {
    func addTwo(input: Int) -> Int {
        return input + 2
    }
}