实现两端的数据同步

当使用 UIViewRepresentable 或 UIViewControllerRepresentable 将 UIKit 组件集成到 SwiftUI 中时,确保 UIKit 端的数据变化能够同步到 SwiftUI 是一个常见的需求。为了实现这一点,你可以通过以下几种方法来处理:

1. 使用 @Binding 和 Coordinator

这是最常见的方法之一。通过在 Coordinator 中监听 UIKit 端的数据变化,并将这些变化同步回 SwiftUI 视图的绑定属性。

示例

假设你有一个 UIKit 组件 WAHWDMP4PlayerOriginView,它会触发某些事件或改变内部状态。你需要将这些变化同步到 SwiftUI 的视图中。

struct WAHWDMP4PlayerView: UIViewRepresentable {
    @Binding var sources: [String]
    @Binding var playerState: PlayerState // 假设这是一个表示播放器状态的枚举

    func makeUIView(context: Context) -> WAHWDMP4PlayerOriginView {
        let playerView = WAHWDMP4PlayerOriginView()
        playerView.delegate = context.coordinator // 设置代理为 Coordinator
        return playerView
    }

    func updateUIView(_ uiView: WAHWDMP4PlayerOriginView, context: Context) {
        uiView.updateSources(sources: sources)
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    class Coordinator: NSObject, WAHWDMP4PlayerOriginViewDelegate {
        private var parent: WAHWDMP4PlayerView

        init(_ parent: WAHWDMP4PlayerView) {
            self.parent = parent
        }

        // 实现委托方法,处理数据变化
        func playerStateChanged(to newState: PlayerState) {
            parent.playerState = newState // 更新绑定属性
        }
    }
}

// 假设这是你的 UIKit 视图类
protocol WAHWDMP4PlayerOriginViewDelegate: AnyObject {
    func playerStateChanged(to newState: PlayerState)
}

class WAHWDMP4PlayerOriginView: UIView {
    weak var delegate: WAHWDMP4PlayerOriginViewDelegate?

    // 当播放器状态改变时调用此方法
    func changePlayerState(to newState: PlayerState) {
        // 更新内部状态逻辑
        delegate?.playerStateChanged(to: newState) // 通知 Coordinator
    }

    // 其他代码...
}

2. 使用 @Published 和 ObservableObject

如果 UIKit 端的数据变化需要更复杂的处理,或者你有多个状态需要管理,可以考虑创建一个符合 ObservableObject 协议的对象,并使用 @Published 属性包装器来发布变化。

示例

class PlayerViewModel: ObservableObject {
    @Published var sources: [String] = []
    @Published var playerState: PlayerState = .idle

    // 其他逻辑...
}

struct WAHWDMP4PlayerView: UIViewRepresentable {
    @ObservedObject var viewModel: PlayerViewModel

    func makeUIView(context: Context) -> WAHWDMP4PlayerOriginView {
        let playerView = WAHWDMP4PlayerOriginView()
        playerView.delegate = context.coordinator
        return playerView
    }

    func updateUIView(_ uiView: WAHWDMP4PlayerOriginView, context: Context) {
        uiView.updateSources(sources: viewModel.sources)
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(viewModel: viewModel)
    }

    class Coordinator: NSObject, WAHWDMP4PlayerOriginViewDelegate {
        private var viewModel: PlayerViewModel

        init(viewModel: PlayerViewModel) {
            self.viewModel = viewModel
        }

        func playerStateChanged(to newState: PlayerState) {
            viewModel.playerState = newState
        }
    }
}

3. 使用 @State 和回调函数

对于简单的数据同步,你也可以使用 @State 和回调函数来处理。

示例

struct WAHWDMP4PlayerView: UIViewRepresentable {
    @Binding var sources: [String]
    var onPlayerStateChanged: (PlayerState) -> Void

    func makeUIView(context: Context) -> WAHWDMP4PlayerOriginView {
        let playerView = WAHWDMP4PlayerOriginView()
        playerView.delegate = context.coordinator
        return playerView
    }

    func updateUIView(_ uiView: WAHWDMP4PlayerOriginView, context: Context) {
        uiView.updateSources(sources: sources)
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(onPlayerStateChanged: onPlayerStateChanged)
    }

    class Coordinator: NSObject, WAHWDMP4PlayerOriginViewDelegate {
        private var onPlayerStateChanged: (PlayerState) -> Void

        init(onPlayerStateChanged: @escaping (PlayerState) -> Void) {
            self.onPlayerStateChanged = onPlayerStateChanged
        }

        func playerStateChanged(to newState: PlayerState) {
            onPlayerStateChanged(newState)
        }
    }
}

// 在 SwiftUI 视图中使用
struct ContentView: View {
    @State private var playerState: PlayerState = .idle

    var body: some View {
        VStack {
            WAHWDMP4PlayerView(sources: $sources, onPlayerStateChanged: { newState in
                self.playerState = newState
            })
            Text("Current State: \(playerState.rawValue)")
        }
    }
}

关键点总结

  • **@Binding**:用于简单地将 UIKit 端的数据变化同步回 SwiftUI 视图。

  • **Coordinator**:作为桥梁,处理事件和状态变化,并将其传递给 SwiftUI 视图。

  • **@Published 和 ObservableObject**:用于管理更复杂的状态变化,确保所有相关视图都能响应这些变化。

  • **回调函数**:对于简单的场景,可以直接使用回调函数来处理状态变化。

选择哪种方法取决于你的具体需求和应用的复杂度。通常,Coordinator 结合 @Binding 或 ObservableObject 是最常用且灵活的方法。

Last updated