admin管理员组

文章数量:1123696

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 ?

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 ?

Share Improve this question asked yesterday Shawn FrankShawn Frank 5,1332 gold badges20 silver badges39 bronze badges 2
  • Do you need to cast it? Can you just say if self is UIHostingController? If you need to know whether self is one of the specific ui hosting view controllers, then you need to conditionally cast to each one because Swift generics are not covariant. – Paulw11 Commented yesterday
  • You need create common View, that can display ArticleView or RatingView and use it as generic parameter of UIHostingController – Cy-4AH Commented yesterday
Add a comment  | 

2 Answers 2

Reset to default 0

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 {}

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) {
   
}

本文标签: