Swift: Reuse code passing class to parameter - ios

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

Related

can't cast LaunchViewController to UINavigationController

I am trying to check the network status from the AppDelegate.swift instead of checking from LaunchViewController.
I have written showOfflinePage in AppDelegate when I shut down my network I have this error cast
Could not cast value of type
'reachability_playground.LaunchViewController' (0x1095b5f20) to
'UINavigationController' (0x114bb2a20). 2019-01-06
16:42:04.079430-0500 reachability-playground[2781:93635] Could not
cast value of type 'reachability_playground.LaunchViewController'
(0x1095b5f20) to 'UINavigationController' (0x114bb2a20).
private func showOfflinePage() -> Void {
DispatchQueue.main.async {
let storyboard = UIStoryboard(name: "Main", bundle: nil);
let viewController: LaunchViewController = storyboard.instantiateViewController(withIdentifier: "LaunchViewController") as! LaunchViewController;
// Then push that view controller onto the navigation stack
let rootViewController = self.window!.rootViewController as! UINavigationController
rootViewController.pushViewController(viewController, animated: true);
}
}
As per the exception message, your root view controller is an instance of LaunchViewController, not an instance of UINavigationController so the forced downcast fails.
You need to check your storyboard and ensure that the entry point scene is a navigation controller.

iOS (Swift) - Array of UIViewControllers

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

performSegueWithIdentifier not working when being called from new instance of viewController in Swift

My mission
When app receive notification and user taps on the notification i want to redirect the user to the correct View. In my case, SingleApplicationViewController.
Current code
PushNotification.swift - A class with static functions to handle behaviors when receiving Push Notifications
The __getNavigationController returns a specific NavigationController based on a tab -and viewIndex from TabBarController.
internal static func __getNavigationController(tabIndex: Int, viewIndex: Int) -> UINavigationController {
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let window:UIWindow? = (UIApplication.sharedApplication().delegate?.window)!
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
let viewController = storyBoard.instantiateViewControllerWithIdentifier("MainEntry")
window?.rootViewController = viewController
let rootViewController = appDelegate.window!.rootViewController as! UITabBarController
rootViewController.selectedIndex = tabIndex
let nav = rootViewController.viewControllers![viewIndex] as! UINavigationController
return nav
}
The applicationClicked is being called when user click on notification and that method calls on __getApplication to fetch the application from the db with the objectId received in the push notification and then instantiate a GroupTableViewController to perform segue to the SingleApplicationViewController.
(TabbarController -> Navigation Controller -> GroupTableViewController -> SingleApplicationViewController)
What is a bit strange is when I set tabIndex to 0 and viewIndex to 1. The GroupView however is on second tab (tab 1) and the view controller should be the first (0). But when I set them to the corresponding numbers, I receive nil and the application crashes.
I read that you will force the view controller to load when doing _ = groupTableViewController.view and which it actually does. When this is being called, the viewDidLoad -function is being called.
/************** APPLICATION ***************/
static func applicationClicked(objectId: String) {
__getApplication(objectId) { (application, error) in
if application != nil && error == nil {
let nav = __getNavigationController(0, viewIndex: 1)
let groupTableViewController = nav.viewControllers.first as! GroupsTableViewController
_ = groupTableViewController.view
groupTableViewController.performSegueWithIdentifier("GroupTableToApplicationToDetailApplication", sender: application!)
} else {
// Hanlde error
}
}
}
GroupTableViewController.prepareForSegue()
Here I create a new instance of the ApplicationTableViewController, which is a middle step before getting to SingleApplicationViewController
} else if segue.identifier == "GroupTableToApplicationToDetailApplication" {
let navC = segue.destinationViewController as! UINavigationController
let controller = navC.topViewController as! ApplicationViewController
controller.performSegueWithIdentifier("ApplicationsToSingleApplicationSegue", sender: sender as! Application)
}
So, what's not working?
Well, the prepareForSegue in GroupTableViewController is not being called. I use the same code structure on my TimeLineViewController, and almost the exact same code, when getting another Push Notification and it works perfectly. In that case I use tabIndex 0 and viewIndex 0 to get the proper NavigationController.
Please, any thoughts and/or suggestions is more than welcome!
There is change in following method..
internal static func __getNavigationController(tabIndex: Int) -> UINavigationController {
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let window:UIWindow? = (UIApplication.sharedApplication().delegate?.window)!
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
let viewController = storyBoard.instantiateViewControllerWithIdentifier("MainEntry")
window?.rootViewController = viewController
let rootViewController = appDelegate.window!.rootViewController as! UITabBarController
rootViewController.selectedIndex = tabIndex
let nav = rootViewController.selectedViewController as! UINavigationController //This will return navigation controller..
//No need of viewIndex..
return nav
}
you have written
let nav = rootViewController.viewControllers![viewIndex] as! UINavigationController
change to rootViewController.selectedViewController give you UINavigationController.
Here you get navigavtion controller object..In your applicationClicked method nav object might be nil so it can not execute further performsegue code.
Check following method.
/************** APPLICATION ***************/
static func applicationClicked(objectId: String) {
__getApplication(objectId) { (application, error) in
if application != nil && error == nil {
let nav = __getNavigationController(0)//0 is your tab index..if you want 1 then replace it with 1
let groupTableViewController = nav.viewControllers.first as! GroupsTableViewController //Rootview controller of Nav Controller
groupTableViewController.performSegueWithIdentifier("GroupTableToApplicationToDetailApplication", sender: application!) //Perform seque from Root VC...
} else {
// Hanlde error
}
}
}

Downcast from 'UIViewController?' to 'UIViewController' only unwraps optionals; did you mean to use '!'?

I am using below code to set root view controller. But It is giving me error:
let storyboard = UIStoryboard(name:"SignUp", bundle:nil)
let viewController = storyboard.instantiateInitialViewController() as! UIViewController
self.window!.rootViewController = viewController
I am getting error like Downcast from 'UIViewController?' to 'UIViewController' only unwraps optionals; did you mean to use '!'?
I think, It has to do with "as!", but it is introduced in new swift.
Does any one have idea ?
Two ways to do this I suppose
Safer one:
let storyboard = UIStoryboard(name:"SignUp", bundle:nil)
if let viewController = storyboard.instantiateInitialViewController(){
self.window!.rootViewController = viewController
}
edit: removed as? UIViewController
The one suggested by the compiler:
let storyboard = UIStoryboard(name:"SignUp", bundle:nil)
let viewController = storyboard.instantiateInitialViewController()!
self.window!.rootViewController = viewController
Basically the compiler is just letting you know that the as! UIViewController in this code is basically just the same as using one !

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

Resources