Reputation: 4760
I am trying to programatically get all the segues attached to UIViewController using UIStoryboardSegueTemplate and my aim is to get the destination view controller to the segue associated.
So far I have done:
func initViewControllers(){
guard let array = self.value(forKey: "storyboardSegueTemplates") as? [AnyObject] else {
//No segues
return
}
for item in array{
print("\(logClassName): initViewControllers -> Self = \(String(describing: item.self))")
print("\(logClassName): initViewControllers -> Segue Identifier = \(String(describing: item.value(forKey: "identifier")))")
print("\(logClassName): initViewControllers -> Class = \(String(describing: item.value(forKey: "segueClassName")))")
print("\(logClassName): initViewControllers -> Destination = \(String(describing: item.value(forKey: "destinationViewControllerIdentifier")))")
let segueClassName:String = (item.value(forKey: "segueClassName") as? String) ?? ""
if segueClassName.contains("CustomTabSegue"){
print("\(logClassName): appending tabItem VC")
let segueContainer:String = (item.value(forKey: "identifier") as? String) ?? ""
performSegue(withIdentifier: segueContainer, sender: self)
}
}
}
and getting the Destination using override func prepare(for segue: UIStoryboardSegue, sender: Any?)
The way I select the segues I want to catch is by a custom class called CustomTabSegue
The question is: Is there a way to get the destination View controller without performing the segue?
According to this link it seems unlikely but maybe there is something I am missing.
Upvotes: 0
Views: 102
Reputation: 4760
Following the answer of Agent Smith, I have been able to do:
func initViewControllers(){
guard let array = self.value(forKey: "storyboardSegueTemplates") as? [AnyObject] else {
return
}
for item in array{
if let segueClassName = (item.value(forKey: "segueClassName") as? String){
if segueClassName.contains("CustomTabSegue"){
print("\(logClassName): CustomTabSegue")
if let destinationViewController = (item.value(forKey: "destinationViewControllerIdentifier") as? String)?.components(separatedBy: "-").first{
print("\(logClassName): DestinationVC = \(destinationViewController)")
if let addedVC = destinationViewController.getViewController(){
print("\(logClassName): Adding View Controller \(addedVC.logClassName)")
viewControllers.append(addedVC)
}
}
}
}
}
And I have created the following extension
import Foundation
import UIKit
extension String{
func getViewController() -> UIViewController? {
if var appName = Bundle.main.infoDictionary?["CFBundleName"] as? String {
print("CFBundleName - \(appName)")
appName = appName.replacingOccurrences(of: " ", with: "_", options: .literal)
if let viewControllerType = NSClassFromString("\(appName).\(self)") as? UIViewController.Type {
print("String: as UIViewController")
return viewControllerType.init()
}
}
return nil
}
It works as expected but the only problem a now is that if the ViewController in embedded in a UINavigationController it won't detect it
Upvotes: 0
Reputation: 2913
If you created those segues yourself, What I did was, I gave the identifier to the segue as :-
ViewControllerName1 + "To" + ViewControllerName2
After getting the list of segues from storyboardSegueTemplates I separated them with To
and got the name of both source and destination ViewControllers. Then, Converting them to Class type by
NSClassFromString(ClassName: String)
This way you can get the type of classes which are associated with segues but it's impossible to get the instances of destinationViewControllers because they are not initialized until you do :
performSegue(withIdentifier: String, sender: Any?)
Hope it helps!!
Upvotes: 1