can't cast LaunchViewController to UINavigationController - ios

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.

Related

How to obtain reference to a View Controller from UITabBarViewController

EDIT: I was off base in my approach. I'm trying to pass data from one VC to another. The source VC is not controlled by a Tab Bar, so I can't reference the destination VC through it. I am attempting to reference the destination VC thorough the Storyboard, but the data is still nil on the destination VC. I'm using Core Data and wish to pass the ManagedObjectContext to another VC. Here is the code:
......
do {
try self.managedObjectContext.save()
appUserID = user.userID!
} catch {
fatalError("Error: \(error)")
}
}
}
self.passManagedObjectContext()
}
func passManagedObjectContext() {
let profileTableViewController = UIStoryboard(name: "Profile", bundle: nil).instantiateViewController(withIdentifier: "ProfileViewController") as! ProfileTableViewController
profileTableViewController.managedObjectContext = self.managedObjectContext
}
I am passing data from the AppDelegate to other ViewControllers by referencing my TabBarViewControllers stack like so:
let tabBarController = window!.rootViewController as! UITabBarController
if let tabBarViewControllers = tabBarController.viewControllers {
let profileNavController = tabBarViewControllers[4] as! UINavigationController
let profileTableViewController = profileNavController.topViewController as! ProfileTableViewController
profileTableViewController.managedObjectContext = context
}
}
.....
END EDIT
I'm trying to do the same now but from one ViewController to another that is accessed through the tab bar (no segue). The code above does not recognize window!.rootViewController how can I reference the root UITabBarController?
UIViewController has a built-in optional property tabBarController, so inside your view controller you can access the tabBarController like so:
if let tabBarController = tabBarController {
//get the controller you need from
//tabBarController.viewControllers
//and do whatever you need
}
Here is the current list of properties available in the 'Getting Other Related View Controllers' section of Apple's UIViewController documentation:

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

iOS Swift Navigate to certain ViewController programmatically from push notification

I use push notifications to inform the user about different types of events happening in the app. A certain type of push notification should open a special viewcontroller (f.e a notification about a new chat message does navigate to the chat on click)
To achieve this, i tried the following code inside my app delegate:
func applicationDidBecomeActive(_ application: UIApplication) {
if var topController = UIApplication.shared.keyWindow?.rootViewController {
while let presentedViewController = topController.presentedViewController {
topController = presentedViewController
}
topController.tabBarController?.selectedIndex = 3
}
}
It does not move anywhere. What am I missing here?
I wrote a simple class to navigate to any view controller in the view hierarchy from anywhere in one line of code by just passing the class type, so the code you'll write will be also decoupled from the view hierarchy itself, for instance:
Navigator.find(MyViewController.self)?.doSomethingSync()
Navigator.navigate(to: MyViewController.self)?.doSomethingSync()
..or you can execute methods asynchronously on the main thread also:
Navigator.navigate(to: MyViewController.self) { (MyViewControllerContainer, MyViewControllerInstance) in
MyViewControllerInstance?.doSomethingAsync()
}
Here's the GitHub project link: https://github.com/oblq/Navigator
This is what you need.
Use your navigation controller to push your notification view controller
let mainStoryBoard : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let navigationController : UINavigationController = mainStoryBoard.instantiateViewController(withIdentifier: "MainNavigationController") as! UINavigationController
let notifcontrol : UIViewController = (mainStoryBoard.instantiateViewController(withIdentifier: "NotificationViewController") as? NotificationViewController)!
navigationController.pushViewController(notifcontrol, animated: true)
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window?.rootViewController = navigationController
self.window?.makeKeyAndVisible()
The topController was already my TabBarController in this case!

Setting Init VC in App Delegate?

I am trying to init my core data stack with the init VC of my app. To do this I want to pass the core data manager i have created into the first VC upon loading.
I thought this code would make sense to pass the coredatamanager into the VC, however I get errors whichever way i write this code, im sure im missing something simple?
// Initialize Storyboard
let storyboard = UIStoryboard(name: "RoutineController", bundle: Bundle.main)
// Instantiate Initial View Controller
if let viewController = storyboard.instantiateInitialViewController() as? ViewController {
// Configure View Controller
viewController.coreDataManager = coreDataManager
// Set Root View Controller
window?.rootViewController = viewController
}
Error is simply:
Use of undeclared type 'ViewController'
However if i delete 'as? ViewController' I get an error on the following line that viewController has no property coreDataManager.
Is there some sort of delegate i need to define in the viewdidload of the view controller in sending to?
EDIT Revised my code to correct the storyboard ID, however the code inside the {} doesnt seem to execute, i get the printed error i wrote due to the if let failing, so this still isnt the right way to set the viewController...any ideas as to why?
// Initialize Storyboard
let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)
// Instantiate Initial View Controller
if let viewController = storyboard.instantiateInitialViewController() as? RoutineController {
// Configure View Controller
print("SENDING THIS INFO TO THE FIRST VC \(self.coreDataManager)")
viewController.coreDataManager = self.coreDataManager
// Set Root View Controller
window?.rootViewController = viewController
} else {
print("WE COULDNT SET VIEWCONTROLLER AS THE DESIGNATED VC SO MOC WASNT PASSED")
}
This is your problem:
as? ViewController
should be
as! UIViewController
alternatively this should also work:
as! RoutineController
Select the RoutineController in your storyboard and set the storyboard ID
Then use the Storyboard ID here:
if let viewController = storyboard.instantiateViewController(withIdentifier: "<storyboardID>") as? RoutineController {
The solution was that you need to define an identifier in the if let viewController to find it successfully, the working code is as follows:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
if let viewController = storyboard.instantiateViewController(withIdentifier: "TabBarController") as? TabBarController {
viewController.coreDataManager = self.coreDataManager
window?.rootViewController = viewController

Passing value over to next viewController

I am currently writing an app in Swift and I implemented all my UI programatically. I would it kind of exhausting, so recently I decided to use storyboard but I am stuck with a bug.
When passing over the mainContext from the AppDelegate to the FirstViewController, the value of the mainContext is nil. In the first place, when I wrote everything programmatically, my code looked like this:
let vc = FirstViewController()
vc.mainContext = mainContext
window?.rootViewController = vc
But now that I am working with StoryBoard, this is not valid anymore because I have to instantiate the view with its ID, like this:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
var vc = storyboard.instantiateViewControllerWithIdentifier("FirstView") as! FirstViewController
vc.mainContext = mainContext
But in this case, the context is nil. If I don't instantiate the VC like this, my outlets are nil and I get this error:
fatal error: unexpectedly found nil while unwrapping an Optional value
Does someone know a way to pass my mainContext?
You're not accessing the rootViewController, you're creating a new view controller and not doing anything with it, to access the rootViewController replace this
let storyboard = UIStoryboard(name: "Main", bundle: nil)
var vc = storyboard.instantiateViewControllerWithIdentifier("FirstView") as! FirstViewController
vc.mainContext = mainContext
with
if let vc = self.window?.rootViewController as? FirstViewController {
vc.mainContext = mainContext
}

Resources