Passing value over to next viewController - ios

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
}

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.

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:

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

Setting rootViewController then navigate to next view programatically

Initially I have a hierarchy below after login
-> MyCoursesViewController
-> CourseInfo UITabBarController
If the user closes the app, then re-enters, the rootViewController will be the CourseInfo UITabBarController which is correct. However when the user needs to view a different course (exits the course), they can’t go ‘back’ to MyCoursesViewController because its no longer on the stack.
In AppDelegate:
if (inCourse) {
let storyboard : UIStoryboard = UIStoryboard(name: “Main”, bundle: nil)
let courseInfoTabController = storyboard.instantiateViewControllerWithIdentifier(“CourseInfo”) as! UITabBarController
self.window?.rootViewController = courseInfoTabController
} else {
let storyboard : UIStoryboard = UIStoryboard(name: “Main”, bundle: nil)
let myCoursesViewController = storyboard.instantiateViewControllerWithIdentifier(“MyCourses”)
self.window?.rootViewController = myCoursesViewController
}
Is there some way I can put the MyCoursesViewController as the rootViewController then automatically navigate to Course Info UITabBarController just so the MyCoursesViewController is on the hierarchy incase they hit back (exits the course)?
Alternatively is it better if the user exits the course (hit back), we delete the rootViewController somehow and replace with a new rootViewController? Another option is if we just replace the rootViewController, will the old one be freed from memory or is it still referenced somewhere?
e.g.
CourseInfo UITabBarController is currently still rootViewController but now we swap it out with a new one
let mainStoryBoard = UIStoryboard(name: "Main", bundle: nil)
let myCoursesViewController = mainStoryBoard.instantiateViewControllerWithIdentifier(“MyCourses”) as! ViewController
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
appDelegate.window?.rootViewController = myCoursesViewController
In your AppDelegate you can set your hierarchy. Try with something like:
let storyboard : UIStoryboard = UIStoryboard(name: “Main”, bundle: nil)
let myCoursesViewController = storyboard.instantiateViewControllerWithIdentifier(“MyCourses”)
if isInCourse{
let courseInfoTabController = storyboard.instantiateViewControllerWithIdentifier(“CourseInfo”) as! UITabBarController
let navigationBar = UINavigationController()
navigationBar.setViewControllers([myCoursesViewController,courseInfoTabController], animated: false)
self.window?.rootViewController = navigationBar
}else{
self.window.rootViewController = myCoursesViewController
}

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 !

Resources