iOS (Swift) - Array of UIViewControllers - ios

I have an array UIButtons that have a unique tag value. When a given button is pressed, I want to load and present a UIViewController that is also stored in an array of equal length.
The UIViewControllers to be presented are subclasses of a subclass of UIViewController:
class AViewController: UIViewController {}
class BViewController: AViewController {}
class CViewController: AViewController {}
class DViewController: AViewController {}
// ... etc.
I've tried storing the array of AViewController subclasses using the following:
private var array: [AViewController] = [BViewController.self, CViewController.self, DViewController.self]
but I get the error Cannot convert value of type '[BViewController].Type' to specified type '[AViewController]' for the first element.
I will then present BViewController (for instance) using the following:
let ViewController = array[button.tag].self
var viewController: AViewController
viewController = ViewController.init()
viewController.transitioningDelegate = self
viewController.modalPresentationStyle = .custom
present(viewController, animated: true)
Please let me know if this is the incorrect thought process for doing something like this please and thanks for any help.

You need instances
private var array: [AViewController] = [BViewController(), CViewController(), DViewController()]
if the vcs are in IB , then you would do
let b = self.storyboard!.instantiateViewController(withIdentifier: "bID") as! BViewController
let c = self.storyboard!.instantiateViewController(withIdentifier: "cID") as! CViewController
let d = self.storyboard!.instantiateViewController(withIdentifier: "dID") as! DViewController
Then
array = [b,c,d]

lazy var VCArray :[UIViewController] = {
return [VCinst(name: "firstVC"),VCinst(name: "secondVC"), VCinst(name: "thirdVC")]
}()
func VCinst(name:String) -> UIViewController {
return UIStoryboard(name: "Main", bundle: nil).instantiateViewController(identifier: name)
}

Alternate answer if you want to store array of view controllers as a constant.
struct AppConstant {
static let yourViewControllers: [AnyClass] = [AViewController.self,
BViewController.self, CViewController.self]
}

Related

Get another tab's viewcontroller variable in current tab bar - iOS - Swift

I have a tabBarController with below hierarchy
TabBarController
Tab 1 -> Contains Navigation Controller(NavController1) -> ViewController1 -has--> ContainerView --contains--> DisplayedViewControllerTab1 (this is my tab1 view controller displayed)
Variable dataForVC1 is in DisplayedViewControllerTab1
When user taps Tab3 (DisplayedViewControllerTab3), I'm trying to get value of dataForVC1 to pass to tab3 viewController
So far I've tried this
In in TabBarController - didSelect method
var data: ModelData?
if let navController = tabBarController.viewControllers?[0] as? NavController1,
let childNavVC = navController.children.first as? ViewController1 {
//Get container view
let conView = childNavVC.containerView. //This is outlet
//Looking for something like this - struck here
if let displayedVC1 = "Container view's VC as? DisplayedViewControllerTab1 {
data = displayedVC1.dataForVC1
}
}
Kindly advice how to achieve this
You don't need to hustle around with container views. In your ViewController1 simply add references to the DisplayedViewControllerTab1 or other vc's you need and then access them directly.
Your VC code would look something like this.
class ViewController1: UIViewController {
//...
var displayedVC1: DisplayedViewControllerTab1?
//...
}
And then your code now:
var data: ModelData?
if let navController = tabBarController.viewControllers?[0] as? NavController1,
let childNavVC = navController.children.first as? ViewController1 {
data = childNavVC.displayedVc1
}
P.S. For convenience, if you have your own TabBarController class you can add all the references you need when the controller is created or simply have computed properties, so you don't need to go deep in the hierarchy all the time.
In your TabbarViewController class:
var myViewController1: MyViewControllerOne? {
return (viewControllers[0] as? NavController)?.children.first as? MyViewControllerOne
}
var myViewController2: MyViewControllerTwo? {
return (viewControllers[1] as? NavController)?.children.first as? MyViewControllerTwo
}

Direct initializing of a viewController

My Desire Output:
i want to pass data with direct initializing of a second viewController
in my first vc :
class MainViewController : UIViewController {
#IBAction func nextQuestion(_ sender: UIButton ) {
//enter code here
questionIndex += 1
let currentQuestion = exam1[questionIndex]
questionLabel.text = currentQuestion.question
//enter code here
let svc = SecondViewController()
svc.label.text = "some data from mainvc"
}
in my secondvc :
class SecondViewController : UIViewController {
#IBOutlet weak var label : UILabel!
}
// any error is not showed up when I write code an the simulator works. but when it comes to sending data to svc app crashes and gives error " found nil while unwrapping optional"
The problem is that when you do:
let svc = SecondViewController()
You are initializing without the information you put in the Storyboard (assuming you are using storyboards). Hence, so the UILabel is never initialized.
Solution
In order to solve that replace the line:
let svc = SecondViewController()
for
let svc = UIStoryboard(name: "YourStoryboardName", bundle: nil).instantiateViewController(withIdentifier: "YourViewIdentifier") as! SecondViewController

Swift: Reuse code passing class to parameter

I would like to reuse code, so I created redirectToTabBarControllerChild
func redirectToTabBarControllerChild(storyboardName: String, tabBarIndex: Int, segueID: String, viewController: UITableViewController) {
let storyboardMain = UIStoryboard(name: storyboardName, bundle: nil)
let tabBarController = storyboardMain.instantiateViewController(withIdentifier: "TabBarController") as! UITabBarController
window?.rootViewController = tabBarController
tabBarController.selectedIndex = tabBarIndex
let navigationViewContrller = tabBarController.childViewControllers[tabBarIndex] as! UINavigationController
let currentViewContrller = navigationViewContrller.childViewControllers.first as! viewController
currentViewContrller.performSegue(withIdentifier: segueID, sender: nil)
window?.makeKeyAndVisible()
}
The last parameter I would like to pass ProfileViewController for example. But I have an error in this line: let currentViewContrller = navigationViewContrller.childViewControllers.first as! viewController
Use of undeclared type viewController
Does anyone know how I could do it?
The navigationController?.childViewControllers is an array of UIViewControllers. You´re getting the first property which means you need to cast it to as! UIViewController which will force cast it and it will not be an optional anymore.
What you want to do is to cast it to a UITableViewController, so do it like this:
if let vc = navigationViewContrller.childViewControllers.first as? UITableViewController {
// Will succeed if the first is of type UITableViewController
// Use vc in here
}
Replace viewController to UITableViewController

How to pass data to embed ViewController?

I have a code, which must pass data with segue:
let navController : UINavigationController = segue.destinationViewController as! UINavigationController
let viewController : UIViewController = navController.viewControllers[0] as! CTableViewController
viewController.SelectedTypeOfVariable = "G"
But I have the following error:
UIViewController does not have a member named SelectedTypeOfVariable
This worked for me:
let viewController : CTableViewController = navController.viewControllers[0] as! CTableViewController
viewController.SelectedTypeOfVariable = "G"
I think the reason for this is because you are saying your "viewController" variable is of type UIViewController. If your "viewController" variable is of type UIViewController, then it indeed does not have a member named SelectedTypeOfVariable. Your subclass of UIViewController, "CTableViewController" does though and so you need to make sure your variable is of type "CTableViewController"
You can use like this
let viewController = navController.viewControllers[0] as! CTableViewController

Pass messages and/or objects between different storyboards swift

I've two storyboards and need to pass messages and objects. I know how to do it in the same storyboard and with .xib files, but not with two different storyboards.
My code is:
var storyboard = UIStoryboard(name: "RecibosStoryboard", bundle: nil)
var controller = storyboard.instantiateViewControllerWithIdentifier("RecibosStoryboard") as! UINavigationController
self.presentViewController(controller, animated: true, completion: nil).
// If i do: var controller = storyboard.instantiateViewControllerWithIdentifier("RecibosStoryboard") as! = TableRecibosViewController -> fails ->cannot convert TablaRecibosViewController to UINavigationController
// If i do:
/* var controller = storyboard.instantiateViewControllerWithIdentifier("RecibosStoryboard") as! UINavigationController
let vartest: TablaRecibosTableViewController = TablaTablaRecibosTableViewController()
prueba.inicioPrueba(str, strPrueba2: str2) -> two objects are nill
self.presentViewController(controller, animated: true, completion: nil).
Two objects are nill*/
My second storyboard is "RecibosStoryboard" and only has 1 view who class is TablaRecibosViewController and has a contructor method:
class TablaRecibosTableViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet var tablaRecibos: UITableView!
var pruebaMansajes: String?
var pruebaMansajes2: String?
var arrayOfObjectsCellRecibos: [ObjectTableRecibos] = [ObjectTableRecibos] ()
override func viewDidLoad() {
super.viewDidLoad()
tablaRecibos.dataSource = self
tablaRecibos.delegate = self
println("Pruebas satisfactorias1 \(pruebaMansajes) \(pruebaMansajes2)")
}
func inicioPrueba(strprueba1:String, strPrueba2:String){
pruebaMansajes = strprueba1
pruebaMansajes2 = strPrueba2
}
When i execute the App or crash or print two objects = nil
I don't find the way to do. Thanks a lot.
The problem is the following "cannot convert TablaRecibosViewController to UINavigationController". Your TablaRecibosViewController is embedded inside a UINavigationController. Try the following:
if let recibosViewController = (storyboard.instantiateViewControllerWithIdentifier("RecibosStoryboard") as? UINavigationController).viewControllers.first as? TablaRecibosTableViewController {
recibosViewController.pruebaMensajes = "Hola mundo"
}
You were creating a new instance of TablaTablaRecibosTableViewController() which was not associated to the Storyboard, therefore the table view was nil and it crashed.

Resources