【问题标题】:Pass @Published properties from view controllers to SwiftUI将 @Published 属性从视图控制器传递给 SwiftUI
【发布时间】:2020-10-14 16:13:21
【问题描述】:

假设您有一个我想与 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) {
        
    }
}

但是,我无法确定从LegacyViewControllerstate 属性到VCWrapper 公开的state 属性的实际绑定位置。如果LegacyViewController 暴露了一个委托,我可以通过Coordinator 对象实现绑定,但考虑到我不使用委托对象,我不太确定如何执行此操作?

【问题讨论】:

    标签: ios swift swiftui


    【解决方案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?
        }
    }
    

    【讨论】:

    • 这种方法有效,但我收到Modifying state during view update, this will cause undefined behavior. 警告,我在其他几种方法中也见过。
    • 好吧,我不知道您何时/何处修改视图控制器中的状态,但请尝试更新 - 已验证修复此类警告。
    猜你喜欢
    • 1970-01-01
    • 2020-10-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-27
    • 2017-08-08
    相关资源
    最近更新 更多