There are probably multiple solutions to this problem, but one way or another, you’ll need to find a way to keep a reference to or communicate with the UIViewController
. Because SwiftUI views themselves are pretty transient, you can’t just store a reference in the view itself, because it could get recreated at any time.
Tools to use:
-
ObservableObject — this will let you store data in a class instead of a struct and will make it easier to store references, connect data, etc
-
Coordinator — in a
UIViewRepresentable
, you can use a Coordinator pattern which will allow you to store references to theUIViewController
and communicate with it -
Combine Publishers — these are totally optional, but I’ve chosen to use them here since they’re an easy way to move data around without too much boilerplate code.
import SwiftUI
import Combine
struct ContentView: View {
@ObservedObject var vcLink = VCLink()
var body: some View {
VStack {
VCRepresented(vcLink: vcLink)
Button("Take photo") {
vcLink.takePhoto()
}
}
}
}
enum LinkAction {
case takePhoto
}
class VCLink : ObservableObject {
@Published var action : LinkAction?
func takePhoto() {
action = .takePhoto
}
}
class CustomVC : UIViewController {
func action(_ action : LinkAction) {
print("\(action)")
}
}
struct VCRepresented : UIViewControllerRepresentable {
var vcLink : VCLink
class Coordinator {
var vcLink : VCLink? {
didSet {
cancelable = vcLink?.$action.sink(receiveValue: { (action) in
guard let action = action else {
return
}
self.viewController?.action(action)
})
}
}
var viewController : CustomVC?
private var cancelable : AnyCancellable?
}
func makeCoordinator() -> Coordinator {
return Coordinator()
}
func makeUIViewController(context: Context) -> CustomVC {
return CustomVC()
}
func updateUIViewController(_ uiViewController: CustomVC, context: Context) {
context.coordinator.viewController = uiViewController
context.coordinator.vcLink = vcLink
}
}
What happens here:
VCLink
is anObservableObject
that I’m using as a go-between to communicate between views- The
ContentView
has a reference to theVCLink
— when the button is pressed, thePublisher
onVCLink
communicates that to any subscribers - When the
VCRepresented
is created/updated, I store a reference to the ViewController and theVCLink
in itsCoordinator
- The
Coordinator
takes thePublisher
and in itssink
method, performs an action on the storedViewController
. In this demo, I’m just printing the action. In your example, you’d want to trigger the photo itself.