我使用 UIHostingController 将 SwiftUI 视图嵌入到控制器 A 中。控制器 A 从控制器 B 启动。SwiftUI 视图使用 ViewModel 类。在ViewModel中,我订阅了一些发布者,我想将数据发送到控制器A。
//This is the ViewModel file that contains a publisher to receive the video URL upon capture, and I am sending this URL to a controller using PassthroughSubject.
class GenericCameraViewViewModel: ObservableObject {
let xCamSession: XCamSession
var preview: some View {
xCamSession.interactivePreview()
}
private var subscription = Set<AnyCancellable>()
public var cameraEventSubject = PassthroughSubject<GenericCameraResult, Never>()
init(genericCameraConfiguration: GenericCameraConfiguation) {
// Prepare video album cover
xCamSession.videoFilePublisher
.receive(on: DispatchQueue.main)
.map {result -> URL? in
if case .success(let file) = result {
return file.path
} else {
return nil
}
}
.sink(receiveValue: { fileURL in
debugPrint("Receive file url")
self.cameraEventSubject.send(GenericCameraResult(event: .capturedVideo, images: nil, videoFile: fileURL))
// if self.shouldSendData {
// self.xCamSession.terminateSession({ result in
// self.cameraEventSubject.send(GenericCameraResult(event: .capturedVideo, images: nil, videoFile: fileURL))
// debugPrint("Receive file url")
//
// })
// }
})
.store(in: &subscription)
}
}
// a function in the controller to add SwiftUI view and subscribe the subject
// display the measure view as a view controller child
private func addAsAChild(){
//let config = GenericCameraConfiguation(captureMode: .photo,canCaputreMultiplePhotos: true, cameraPosition: .back,cameraPhotoFlash: .off,cameraVideoTorch: .auto)
let viewModel = GenericCameraViewViewModel(genericCameraConfiguration: configuration)
let videoContentView = GenericCameraView(viewModel: viewModel)
viewModel.cameraEventSubject
.receive(on: DispatchQueue.main) // Ensure sink runs on main thread
.sink(
receiveCompletion: { completion in
print("-- completion", completion)
self.cancellables.first?.cancel()
self.dismiss(animated: true)
},
receiveValue: {[weak self] result in
viewModel.shouldSendData = false
switch(result.event){
case .closePressed:
viewModel.cameraEventSubject.send(completion: .finished)
debugPrint("Close Button Pressed")
break
case .donePressed:
debugPrint("Done Button Pressed \(result.images ?? [])")
viewModel.cameraEventSubject.send(completion: .finished)
let capturedImages = result.images ?? []
let arrImagePaths = self?.saveImages(images: capturedImages)
self?.mDelegate?.capturedImagesPath(capturedImages: arrImagePaths ?? [])
break;
case .capturedPhoto:
debugPrint("capturedPhoto Button Pressed \(result.images ?? [])")
let capturedImages = result.images ?? []
let arrImagePaths = self?.saveImages(images: capturedImages)
self?.mDelegate?.capturedImagesPath(capturedImages: arrImagePaths ?? [])
case .capturedVideo:
debugPrint("capturedVideo Button Pressed \(result.videoFile ?? URL.init(string: "https://cameraxaapp.com")!)")
self?.mDelegate?.capturedVideoUrl(videoUrl: result.videoFile)
//viewModel.cameraEventSubject.send(completion: .finished)
}
}
).store(in: &cancellables)
let hostingViewController = HostingController(rootView: videoContentView)
addChildWithView(hostingViewController)
}
为了实现这一目标,我在 ViewModel 中添加了一个 PassthroughSubject 并在控制器 A 中订阅了该主题。我在发布者的 .sink 方法中使用该主题发送数据,并且工作正常。但是,当我再次打开控制器 A 时,会自动调用发布者的 .sink 方法。
SwiftUI 不适用于视图模型对象,因为
View
结构已经是视图模型。您最好为回调事件提供闭包 VideoContentView
,例如
videoContentView.donePressed = {
finished()
}
struct VideoContentView: View {
var donePressed: (() -> Void)?
...