简体   繁体   English

将 @Published 属性从视图控制器传递到 SwiftUI

[英]Pass @Published properties from view controllers to SwiftUI

Suppose you have a legacy view controller that I'd like to use with SwiftUI.假设您有一个我想与 SwiftUI 一起使用的旧视图控制器。 The view controller has one @Published property that contains it current state:视图控制器有一个包含当前状态的 @Published 属性:

class LegacyViewController: UIViewController {
    enum State {
        case opened
        case closed
        case halfOpened
    }
    
    @Published var state: State
    
    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
        self.state = .closed
        super.init(nibName: nil, bundle: nil)
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // state is changed after some time
    }
}

Ideally, I'd like to use it with SwiftUI like this:理想情况下,我想像这样在 SwiftUI 中使用它:

struct ContentView: View {
    @State var state: LegacyViewController.State
    
    var body: some View {
        VCWrapper(state: $state).overlay (
            Text("\(state)")
        )
    }
}

which would mean that I need to implement UIViewControllerRepresentable protocol:这意味着我需要实现UIViewControllerRepresentable协议:

struct VCWrapper: UIViewControllerRepresentable {
    @Binding var state: LegacyViewController.State
    
    func makeUIViewController(context: Context) -> LegacyViewController {
        let vc = LegacyViewController(nibName: nil, bundle: nil)
        /// where to perform the actual binding?
        return vc
    }
    
    func updateUIViewController(_ uiViewController: LegacyViewController, context: Context) {
        
    }
}

However, I'm having trouble figuring out where to do the actual binding from state property of the LegacyViewController to the state property exposed by VCWrapper .然而,我无法搞清楚在哪里做,从实际的结合state的财产LegacyViewControllerstate通过公开的属性VCWrapper If LegacyViewController exposed a delegate, I could implement the binding through the Coordinator object, but I'm not so sure how to do this considering that I don't use a delegate object?如果LegacyViewController公开了一个委托,我可以通过Coordinator对象实现绑定,但考虑到我不使用委托对象,我不太确定如何做到这一点?

Here is possible solution - use Combine .这是可能的解决方案 - 使用Combine Tested with Xcode 12 / iOS 14.使用 Xcode 12 / iOS 14 测试。

import Combine

struct VCWrapper: UIViewControllerRepresentable {
    @Binding var state: LegacyViewController.State
    
    func makeUIViewController(context: Context) -> LegacyViewController {
        let vc = LegacyViewController(nibName: nil, bundle: nil)

        // subscribe to controller state publisher and update bound
        // external state
        context.coordinator.cancelable = vc.$state
            .sink {
               DispatchQueue.main.async {
                  _state.wrappedValue = $0
               }
            }

        return vc
    }
    
    func updateUIViewController(_ uiViewController: LegacyViewController, context: Context) {
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator()
    }
    
    class Coordinator {
        var cancelable: AnyCancellable?
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM