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

时间:2020-10-14 16:13:21

标签: ios swift swiftui

假设您有一个旧的视图控制器,我想与SwiftUI一起使用。视图控制器具有一个@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
    }
}

理想情况下,我想像这样在SwiftUI中使用它:

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

这意味着我需要实现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) {
        
    }
}

但是,我在弄清楚从state的{​​{1}}属性到LegacyViewController公开的state属性的实际绑定时遇到了麻烦。如果VCWrapper公开了一个委托,我可以通过LegacyViewController对象来实现绑定,但是考虑到我不使用委托对象,我不确定如何做到这一点?

1 个答案:

答案 0 :(得分:1)

这是可能的解决方法-使用Combine。在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?
    }
}