11

I'm wondering if there's any way to start using SwiftUI in a legacy project and still be able to navigate back and forth SwiftUI scenes. That is, let's imagine I just want to support the last iOS 13 for a project I've been working on for the last year. Everything is built upon UIKit and navigations happen the usual way presenting or pushing viewcontrollers.

Now I want to start using SwiftUI so I enable the option in the General of my project, target iOS 13, get my SceneDelegate and my new key-value pair in Info.plist. In order to navigate to a Swift UI scene, I can just push a UIHostingViewController whose rootView will be my newly designed SwiftUI View. But how can I use NavigationLink to push an old UIKit view controller?

class ViewController: UIViewController {

    @IBAction func userDidTapGo(_ sender: Any) {
        let contentView = ContentView()
        navigationController?.pushViewController(UIHostingController(rootView: contentView), animated: true)
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        title = "UIKit"
    }
}

struct ContentView: View {
    var body: some View {
        NavigationView {
            NavigationLink(destination: /* what should be here?? */) {
                Text("Go to UIKit")
            }

        }.navigationBarTitle("Swift UI")
    }
}
Fernando
  • 751
  • 2
  • 13
  • 27
  • My advice? If your project is a `Storyboard` project, **do not** make your root VC be a `UIHostingViewController` or the root view be a SwoftUI `View`. Period. Since you have a storyboard and a `UINavigationController` already working, just *navigate* (or push) the hosting VC onto the stack and use `Compose` or `Notifications` to navigate from there. In other words, get rid of the `NavigationView` in your `ContentView`, change your `NavigationLink` to be a SwiftUI `Button`, and set it's action to tell your UIKit navigation to push/pop the stack. –  Sep 17 '19 at 12:56
  • Is there a way to get the navigation controller in a SwiftUI View to push or pop the stack? Or would I have to pass it as an initializer argument? – Fernando Sep 17 '19 at 13:33
  • First, I didn't downvote your question - I think I understand what you're asking. And if so, it's something that's (probably?) not possible. (Yet?) But think through something deeper - the complexity of everything you want. Why not start with a SwiftUI app if you are taking your legacy app into some kind of fork that only supports iOS 13? Why not port your UIKit views and VCs into representable views? Finally, if you *must* keep your **iOS 13** app as something that is more UIKit than SwiftUI, why not let *navigation* something that is deeply tied to everything, be part of that? Cont. –  Sep 17 '19 at 13:52
  • #2: In the end, SwiftUI **is not** a "layer" on top of UIKit (nor is the reverse true). It's truly a separate stack - in Xcode, it's part of the second screen when you define your new project. I've given you what I think is a working option. And if you really are forking a UIKit app targeting iOS 12 and under, it *should* work - just move the navigation from SwiftUI to UIKit, and communicate between your different stacks through Combine or notifications. One last comment.... –  Sep 17 '19 at 13:57
  • #3: I"m actually doing the opposite - my SwiftUI app (not legacy) embeds a UINavigationController with two table views because I'm not happy with how raw things like layout and customizing a navigation controller work. While I asked a question about communicating a UIButton click to SwiftUI (and had a really good suggestion) I ended up going back to something I could get working - Notifications. It's a single view SwiftUI app, but where I needed navigation, it's a "child subview" that's a `UIViewControllerRepresentable` that subclasses `UINavigationController`. I sincerely wish you luck! –  Sep 17 '19 at 14:03
  • Thanks for you comments, @dfd. Really. I don't understand why people downvoted my question, perhaps it's my English. Surely I wouldn't target iOS 13 and remove support for older versions just to import SwiftUI. I was just wondering, what will happen in 2-3 years when the last version supported is iOS 13. Will it be possible to include this framework in legacy projects that originally worked with UIKit? I agree that right now it is not possible or at least, too complicated and nonsense. – Fernando Sep 17 '19 at 19:46
  • 2
    I think this should answer your question: https://stackoverflow.com/questions/57965840/segue-to-uiviewcontroller-from-swiftui-view – Sebastian Sep 17 '19 at 20:01
  • 1
    To your last question I'd say look to the past. Cocoa/Carbon, AppKit/UIKit, and in 2 days, AppKit/UIKit/WatchKit/SwiftUI. There's no doubt - none - that *someday* it will all be SwiftUI. But when Carbon lasted 8 years (killed with 64 bit) and AppKit is still around, and, as Apple proudly points out a few times a year, UIKit is a billion $$ industry with millions of apps... well, I don't know how old you are but you may be retired before UIKit goes away! (And I'm only talking software, not OS, not hardware.) –  Sep 17 '19 at 20:28

1 Answers1

1

You'll need to wrap you old view controllers in a UIViewControllerRepresentable wrapper. There is a nice tutorial by Apple: Interfacing with UIKit.

It works great, lets you reuse old code instead of rewriting everything from scratch.

Yonat
  • 4,382
  • 2
  • 28
  • 37