Show view controller from main storyboard - swift

I have a case in one of my Swift files which runs the following method:
case .editProfile:
vc = PoiDetailViewController()
self.navigationController?.popViewController(vc,animated: true)
It doesn't seem to work when I run the code.
The view controller is located on the main storyboard and I would like PoiDetailViewController to display when this case is called.

If I understand it correctly, you should be able to achieve what you're looking for by present in your code. Like so:
case .editProfile:
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyBoard.instantiateViewController(withIdentifier: "PoiDetailViewController") // or whatever identifier you have given it
self.present(vc, animated: true, completion: nil)
That should work, however, make sure you set a storyboard ID for your view controller in the identity inspector.
No segues are required.
To set up a storyboard ID click on the View Controller you would like to use (in this case, PoiDetailViewController) and click the identity inspector icon and set a storyboard ID where it asks. I have attached an image so you can see where it needs to go (in the field marked 'Storyboard ID')
Hope that helps.

As per my Understanding you need to pop to specific View Controller if it is in stack and if not then you need to push to that controller
var loginVCFound:Bool = false;
let navigationController : UINavigationController! = self.window!.rootViewController as! UINavigationController;
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil);
let viewControllers: [UIViewController] = navigationController.viewControllers
for aViewController in viewControllers {
if aViewController is LoginVC {// Pass the name of your controller here
loginVCFound = true;
navigationController.popToViewController(aViewController, animated: true)
break;
}
}
if !loginVCFound { // change the identifier and VC with yours
let objLoginVC = mainStoryboard.instantiateViewController(withIdentifier: "LoginVC") as! LoginVC
navigationController.pushViewController(objLoginVC, animated: true)
}

Related

Navigation bar missing after tapping on remote notification

I have a side menu in app so on clicking the notification I navigate to view controller but cannot navigate to other VC's as it's not showing the navigation bar.
I've done this in my App Delegate and also have a navigation controller in my storyboard.
let sb = UIStoryboard(name: "Main", bundle: nil)
let otherVC = sb.instantiateViewController(withIdentifier: "messageview") as! MessageViewController
window?.rootViewController = otherVC;
func application(_ application: UIApplication,didReceiveRemoteNotification userInfo: [AnyHashable: Any],fetchCompletionHandler completionHandler:#escaping (UIBackgroundFetchResult) -> Void) {
let state = application.applicationState
if state == .inactive || state == .background {
let sb = UIStoryboard(name: "Main", bundle: nil)
let otherVC = sb.instantiateViewController(withIdentifier: "messageview") as! MessageViewController
window?.rootViewController = otherVC
print("background")
} else {
print("foreground")
}
}
Of course the navigation bar is removed; the view controller needs to be embedded in a navigation controller.
Try this:
let sb = UIStoryboard(name: "Main", bundle: nil)
let otherVC = sb.instantiateViewController(withIdentifier: "messageview") as! MessageViewController
// (actually, you don't need to cast to MessageViewController here;
// the returned reference already is guaranteed to at least be a
// UIViewController instance; you don't need more specificity in this
// case --i.e, embed in navigation)
let navigation = UINavigationController(rootViewController: otherVC)
window?.rootViewController = navigation
Note: This will present a fresh navigation with your view controller as the root. You will not be able to "navigate back" to any other screens that normally preceed it when navigating manually from your app's initial screen.
If you need to recreate a specific location within your navigation hierarchy, you will need to instantiate all previous view controllers up to the one you want to show, and set them instantly as the contents of the navigation stack.
Dummy example:
let first = UIStoryboard(name: "First", bundle: nil).instantiateInitialViewController()
let second = UIStoryboard(name: "Second", bundle: nil).instantiateInitialViewController()
let top = UIStoryboard(name: "Mail", bundle: nil).instantiateInitialViewController()
let vcs = [first, second, top]
let navigation = UINavigationController()
navigation.setViewController(vcs, animated: false)
window?.rootViewController = navigation
(this example assumes each VC lives in a separate storyboard, but you can also use instantiateViewController(withIdentifier:_) if that fits your setup)
Now, you can go back to "Second" and "First" using the navigation controller's back button.

Programmatically Segue Between Views in Different Storyboard Files

I have a view HostViewController in Host.storyboard and, in storyboard I am able to segue to AttendDetailViewController in Main.storyboard. However, I want to do this programmatically as follows:
private func attendDetailViewControllerSegue(event: CAEvent) {
let vc = AttendDetailViewController(nibName: "AttendDetailViewController", bundle: nil)
vc.event = event
navigationController?.pushViewController(vc, animated: true)
}
However, when I run this I get the following error:
'NSInternalInconsistencyException', reason: 'Could not load NIB in bundle: 'NSBundle ... with name 'AttendDetailViewController''
I have tried every solution on the internet for this problem, and I feel it might have something to do with the Views being in different storyboards.
Any thoughts on how to do this segue without an exception?
You have to get the storyboard from the bundle:
var hostStoryboard = UIStoryboard(name: "Host", bundle: Bundle.main)
Then, instantiate and present the view controller:
let someViewController = hostStoryboard?.instantiateViewController(withIdentifier: "AttendDetailViewController") as? AttendDetailViewController
self.navigationController?.present(attendDetailViewController!, animated: true)
Don't forget to set the AttendDetailViewController's storyboard identifier in the storyboard.
I also recommend you safely unwrap attendDetailViewController before using it:
let someViewController = hostStoryboard?.instantiateViewController(withIdentifier: "AttendDetailViewController") as? AttendDetailViewController
if let vc = attendDetailViewController {
self.navigationController?.present(vc, animated: true)
}
1- to load from xib ( used when there is AttendDetailViewController.xib file in your project )
let vc = AttendDetailViewController(nibName: "AttendDetailViewController", bundle: nil)
2- to load from storyboard ( used when the vc is inside a storyboard )
let vc = UIStoryboard(name: "Host", bundle: nil)!.instantiateViewController(withIdentifier: "vciD") as? AttendDetailViewController
3- load programmatically ( used when the vc layout is created programmatically )
let vc = AttendDetailViewController()

Handling multiple view controllers in swift 4

newbie here... my root view controller has the following code:
func showVC1() {
let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let vc1 = storyBoard.instantiateViewController(withIdentifier: "first")
self.present(vc1, animated:true, completion:nil)
}
func showVC2() {
let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let vc2 = storyBoard.instantiateViewController(withIdentifier: "second")
self.present(vc2, animated:true, completion:nil)
}
I can call these functions in either order, the first works fine, but the second will give me an error like "Attempt to present on whose view is not in the window hierarchy!"
I think I want to keep all of my code in the root vc that contains these functions. How can I make this work?
I'm also concerned that each time I call these functions I'll be creating new vc instances which will use more memory. Is there a way to keep a reference to these vc's outside of these functions? And will that solve the hierarchy issue?
Yes, second gives an error because you are trying to present two view controller at the same time from root view controller.
You can create lazy references to these view controllers
lazy var firstViewController : FirstViewController = {
let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let vc1 = storyBoard.instantiateViewController(withIdentifier: "FirstViewController") as! FirstViewController
return vc1
}()
#IBAction func buttonPressed(_ sender: Any) {
self.present(firstViewController, animated:true, completion:nil)
}
Instead of presenting a new view controller try to push that one into the navigation stack like
self.navigationController.pushViewController(controller, animated: false)
Because if you present anything on your controller it will not continue the navigation. which will lead to crash

cannot instantiante and push to another view controller

i have collection view and if cell selected, it downloading a pdf file. After download completed and select the cell again, it push to another view controller. But it doesnt push, can someone explain why?
here's my code
if self.percentProgressFinal == 1.0 { //download complete
print("SUCCESS")
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("NEXT")
self.navigationController?.pushViewController(vc, animated: true)
} else {
print("still downloading")
}
It successful printing "SUCCESS" but the code wont execute. I Also try use present and this
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let nextViewController: redirectMagazineViewController = storyBoard.instantiateViewControllerWithIdentifier("NEXT") as! redirectMagazineViewController // my second view controller name
self.navigationController?.pushViewController(nextViewController, animated: true)
and still doesnt work. I'm sure my storyboard id is "NEXT".
Seems like you don't have navigation controller embedded.
Did you check the button " use storyboard id" on your Identity Inspector view controller?

how to call existing navigationcontroller in Swift

I have 3 items in my storyboard. 1. viewController (A) connected to 2. Navigation controller and 3. viewController (B) is NOT connected to anything
All 3 items have restoration identifiers set in the storyboard.
viewController (B) is the initial view controller.
I am trying in B to get the navigation controller that A is attached to, but always returns nil:
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyBoard.instantiateViewControllerWithIdentifier("viewControllerA") as! ViewControllerA
print(vc.navigationController?) // always prints nil
why!?
UPDATE#1
I can't declare a UINavigationController like a view controller. I've tried setting navigationcontroller with the id of 'myNavigationController' as storyboardID:
When storyboard, I get this error
let navigationController = storyBoard.instantiateViewControllerWithIdentifier("myNavigationController") as! UINavigationController
print(self.navigationController!) // fatal error: unexpectedly found nil while unwrapping an Optional value
I've also tried setting the id in restoration identifier, It bombed earlier at the instantiating line
#ColdLogic, see what hits I get when I search the entire project for that identifier:
Because you never instantiated the navigation controller, you instantiated view controller A. You would want something like this if you want both the nav controller and the view controller to be setup like they are in the storyboard
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let navigationController = storyBoard.instantiateViewControllerWithIdentifier("YourNavControllerIdentifier") as! UINavigationController
let vc = navigationController.topViewController as! ViewControllerA
Your code directly instantiates an object of type ViewControllerA. Which, unless you setup logic to do it, does not have a navigation controller by default.
This Worked for me!
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let navigationController = storyBoard.instantiateViewController(withIdentifier: "HomeNavigationContoller") as! UINavigationController
let viewController = storyBoard.instantiateViewController(withIdentifier: "HomeViewController") as! HomeViewController
navigationController.pushViewController(messageVC, animated: true)
self.present(navigationController, animated: true, completion: nil)
Use NavigationController identifier to access the NavigationController and ViewController A is already attached to it, so it will automatically get loaded to NavigationController