Apr 28, 2024 iOS

Calling functions from UIViewController in SwiftUI

Certainly! When working with SwiftUI, you might need to interact with functions from a UIViewController. Let’s explore a few approaches to achieve this:

  1. Using ObservableObject and Coordinator:
    • Create an ObservableObject (let’s call it VCLink) to act as a bridge between your SwiftUI view and the UIViewController.
    • Define an enum (e.g., LinkAction) to represent the actions you want to perform.
    • In your SwiftUI view, use @StateObject to hold an instance of VCLink.
    • Use the .sheet(isPresented:content:) modifier to present the UIViewController (your new view) when a button is pressed.
    • Inside the UIViewController, handle the action based on the enum value.
    • Here’s a simplified example
import SwiftUI
import Combine

enum LinkAction {
    case takePhoto
}

class VCLink: ObservableObject {
    @Published var action: LinkAction?

    func takePhoto() {
        action = .takePhoto
    }
}

class CustomVC: UIViewController {
    func action(_ action: LinkAction) {
        switch action {
        case .takePhoto:
            print("Taking a photo!")
            // Implement your logic here
        }
    }
}

struct VCRepresented: UIViewControllerRepresentable {
    var vcLink: VCLink

    class Coordinator {
        var vcLink: VCLink? {
            didSet {
                cancelable = vcLink?.$action.sink { action in
                    guard let action = action else { return }
                    self.viewController?.action(action)
                }
            }
        }

        var viewController: CustomVC?
        private var cancelable: AnyCancellable?
    }

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

    func makeUIViewController(context: Context) -> CustomVC {
        CustomVC()
    }

    func updateUIViewController(_ uiViewController: CustomVC, context: Context) {
        context.coordinator.viewController = uiViewController
        context.coordinator.vcLink = vcLink
    }
}

struct ContentView: View {
    @StateObject var vcLink = VCLink()

    var body: some View {
        VStack {
            Text("Main View")
                .font(.largeTitle)
                .padding()

            Button("Take Photo") {
                vcLink.takePhoto()
            }
            .padding()
            .background(Color.blue)
            .foregroundColor(.white)
            .cornerRadius(10)

            VCRepresented(vcLink: vcLink)
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
  1. Using NavigationView and NavigationLink:
    • Wrap your main view in a NavigationView.
    • Use a NavigationLink to navigate to the new view when a button is pressed.
    • You can hide the navigation bar if needed.
    • Example:
import SwiftUI

struct ContentView: View {
    var body: some View {
        NavigationView {
            VStack {
                Text("Main View")
                    .font(.largeTitle)
                    .padding()

                NavigationLink(destination: NewView()) {
                    Text("Show New View")
                }
                .padding()
                .background(Color.blue)
                .foregroundColor(.white)
                .cornerRadius(10)
            }
            .navigationBarTitle("") // Hide the navigation bar title
            .navigationBarHidden(true) // Hide the navigation bar
        }
    }
}

struct NewView: View {
    var body: some View {
        Text("New View")
            .font(.title)
            .padding()
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}