cannot instantiante and push to another view controller - swift

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?

Related

Instantiating deep View Controller with Tab bar and Navigation

I am using Xcode 11 and Swift 5.
Upon receiving an APNS notification, I need to jump to a view controller deep in my storyboard from AppDelegate. This viewController (chatVC) is behind a tabbar and a navigation controller and several other view controllers. See the image below. I know how to check the notification for tags and how to use launchOptions in AppDelegate to trigger the jump. But I am struggling with how to establish the context for that last view controller so that the user can use the back button all the way back to the tab bar controller.
I have read many SO answers, and tried many approaches but none seem to have the same embedding of a nav controller inside a tab bar controller. Here is my code in AppDelegate (after reading the tag in the notification):
if tag == "CS" {
// Set up a Chat View Controller.
if let chatVC = UIStoryboard(name: "Main", bundle: .main).instantiateViewController(withIdentifier: Constants.Storyboard.chatVC) as? NewChatViewController,
let tabBarVC = UIStoryboard(name: "Main", bundle: .main).instantiateViewController(withIdentifier: Constants.Storyboard.tabBarController) as? UITabBarController,
let csVC = UIStoryboard(name: "Main", bundle: .main).instantiateViewController(withIdentifier: Constants.Storyboard.csViewController) as? CustomerServiceViewController,
let helpVC = UIStoryboard(name:"Main", bundle: .main).instantiateViewController(withIdentifier: Constants.Storyboard.helpVC) as? HelpViewController
{
// Set the customer service document Id.
chatVC.cs = cs
// Make the tabBarVC the Root View Controller
self.window?.rootViewController = tabBarVC
self.window?.makeKeyAndVisible()
// Select the Favorites Index.
tabBarVC.selectedIndex = 0
// Push the Customer Service VC on top.
tabBarVC.show(csVC, sender: Any?.self)
// Push the Help VC on top of Customer Service VC.
csVC.show(helpVC, sender: Any?.self)
// Push the the chat detail page on top.
helpVC.show(chatVC, sender: Any?.self)
}
}
}
return true
What can I do to jump to the chatVC and set up the navigation context beneath it so the back button can be used?
Here is how you can do it:
guard let tabBarVC = UIApplication.shared.windows.filter( {$0.rootViewController is UITabBarController } ).first?.rootViewController as? UITabBarController else { return }
tabBarVC.selectedIndex = 0 //you can select another tab if needed
guard let chatVC = UIStoryboard(name: "Main", bundle: .main).instantiateViewController(withIdentifier: Constants.Storyboard.chatVC) as? NewChatViewController else { return }
if let navController = tabBarVC.viewControllers?[0] as? UINavigationController {
navController.pushViewController(chatVC, animated: true)
}
You can also pass objects from your notification to your chatVC here before pushing it, in case you need to do that.
Hope this works for you!

Swift - How switch between storyboards with back button?

I'm in a storyboard and I need to go to another storyboard by tapping a button. Well, this I've already done, but I need to go back to previous storyboard. Here is my code:
func goContact() {
let storyboard = UIStoryboard(name: "FAQ", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "ContactViewController")
self.navigationController?.show(vc, sender: nil)
}
By tapping a button on my UITableViewCell (where I have a protocol), this function (goContact) is called and I switch to another storyboard (FAQ). But, how can I go back to main.storyboard?
I've already tried do this too:
func goContact() {
let storyboard = UIStoryboard(name: "FAQ", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "ContactViewController")
self.navigationController?.show(vc, sender: nil)
// self.navigationController?.pushViewController(vc, animated: true)
// self.present(vc, animated: true, completion: nil)
}
Use only storyboard property , it references to Main storyboard of the app or you can write it like let storyboard = UIStoryboard(name: "Main", bundle: nil)
To go back after push do
self.navigationController?.popViewController(animated: true)
You should push your new view controller onto the navigation controller using push, like in your commented-out code. That will cause the new view controller to have a back button, which will pop it for you without needing any extra code.

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()

Show view controller from main storyboard

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

How to reset/restart viewcontroller in Swift?

I want to have a button on my navigation bar "Reset" and I would like this to be connected to an IBAction to sort of "restart" the controller.
I have some segues from another controller that changes some aspects of the viewcontroller (that has a collectionview) and I want the user to be able to start over. Does anyone have any suggestions as to how to proceed?
If you embed navigation controller to your view controller then you can use this code:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("ViewController")
let viewcontrollers = self.navigationController.viewControllers
viewcontrollers.removeLast()
viewcontrollers.append(vc)
self.navigationControllers?.setViewControllers(viewcontrollers, animate: true)
You can change rootViewController of your application:
UIApplication.shared.keyWindow?.rootViewController = UIViewController()
This is how I do it in Swift 2.1 with my Home view inside a UINavigationController:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let homeVC = storyboard.instantiateViewControllerWithIdentifier("HomeViewController")
self.navigationController?.presentViewController(homeVC, animated: false, completion: nil)
self.navigationController?.dismissViewControllerAnimated(false, completion: nil)