skip to Main Content

I have a custom UINavigationController which performs some pushing and popping actions.

I using SwiftUI within a UIKit application so a few of the view controllers within the UINavigationController are UIHostingControllers

In various parts of my code I have UIHostingController(rootView: ArticleView()) or UIHostingController(rootView: RatingView()) and some others

I wanted to specifically identify if the Navigation controller was going to push the article view or the rating view so what I did was:

protocol TabBarCompatible: View { }

extension ArticleView: TabBarCompatible { }

extension RatingView: TabBarCompatible { }

Then when I am going through the view controllers in my Navigation controller, I check to see if the destination is like one of the above:

if let destinationView = self as? UIHostingController<AnyView>,
   destinationView.rootView is any TabBarCompatible

Now the cast to UIHostingController<AnyView> itself fails which probably could succeed if when I created the SwiftUI views, I would need to do UIHostingController(rootView: AnyView(ArticleView())) – however:

  • What I really wish to check is `if let destinationView = self as? UIHostingController
  • I prefer not to wrap to AnyView unless its the last resort as I will have to do this in many places

Another option could also be to hold all the possibilities I wish to check in an array and keep

let swiftUIControllers = [UIHostingController<ArticleView>, UIHostingController<RatingView>]

// loop through the swiftUIControllers and compare the current controller using isKind(of: )

Is there any other / better way to cast a UIViewController to a UIHostingController generically without knowing the rootView of the UIHostingController ?

2

Answers


  1. If you just want to check if the rootView conforms to TabBarCompatible and don’t care about anything else about rootView, you can introduce a new protocol like this:

    protocol TabBarCompatibleViewController: UIViewController {}
    
    extension UIHostingController: TabBarCompatibleViewController where Content: TabBarCompatible {}
    

    Then you can check if destination is (any TabBarCompatibleViewController).

    If you remove the : View constraint on TabBarCompatible, you can reuse TabBarCompatible instead of writing a new protocol,

    extension UIHostingController: TabBarCompatible where Content: TabBarCompatible {}
    
    Login or Signup to reply.
  2. You can refer to the following implementation.

    protocol TabBarCompatible: View { }
    
    extension ArticleView: TabBarCompatible { }
    
    extension RatingView: TabBarCompatible { }
    
    protocol HostingCompatible {
        associatedtype ViewType: TabBarCompatible
        var rootView: ViewType { get }
    }
    
    extension UIHostingController: HostingCompatible where Content: TabBarCompatible { }
    

    You can use it like this

    if let destinationView = self as? (any HostingCompatible) {
       
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search