As you can see in the picture, there're 3 controllers at the bottom which are (HomeTableViewController, NavigationViewController and NewsViewController)
HomeTableViewController is the Main Page which I'm using the SWRevealViewController and set it as a front page. (sw_front)
After I've selected a row in HomeTableViewController, it can navigate to NewsTableViewController. However, I've added a back button in the NewsViewController to navigate back to the previous page which is HomeTableViewController, I'm not manage to do that with this code.
In the HomeTableViewController navigate to NewsViewController by selected a row
#IBAction func btnBack(sender: AnyObject)
{
let home = HomeTableViewController()
self.presentViewController(home, animated: true, completion: nil)
}
In the NewsViewController press back button back to previous page
#IBAction func btnBack(sender: AnyObject)
{
let home = HomeTableViewController()
self.presentViewController(home, animated: true, completion: nil)
}
If I pressed the back button in the NewsViewController, this error appeared.
fatal error: unexpectedly found nil while unwrapping an Optional value
self.revealViewController().rearViewRevealWidth = 200
This code has an error and is located in the HomeTableViewController.
I hope that someone could help me on this. Thank you.
You need to dismiss the presented viewController:
#IBAction func btnBack(sender: AnyObject)
{
let home = HomeTableViewController()
self.dismissViewControllerAnimated(true, completion:nil);
}
You are getting this error because you are creating new HomeTableViewController in btnBack (and this new controller probably doesn't have revealViewController). There is no need to do this. You can just call self.dismissViewControllerAnimated(true, completion:{}); as Islam Q. suggested:
#IBAction func btnBack(sender: AnyObject)
{
self.dismissViewControllerAnimated(true, completion:nil);
}
https://github.com/John-Lluch/SWRevealViewController/issues/516#issuecomment-160590440
This solve my issue.
Delete the navigation controller between the Home and News Controller, and use the push Segue from Home to NewsViewController.
Related
I have the code to go to the next page and show the tabbar when I click the button.
#IBAction func moveBtn(_ sender: Any) {
guard let next = self.storyboard?.instantiateViewController(withIdentifier: "nextPage") as? nextPageCon else {
return
}
self.definesPresentationContext = true
next.modalPresentationStyle = .overCurrentContext
self.present(next, animated: false)
}
My question is, when I go to another page using the tab bar on the next page and then return, I want to show the main page.
Currently, when I move using the tab bar and then come back, the next page is displayed as it is.
How can I fix it?
Add this to your nextPageCon view controller:
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.presentingViewController?.dismiss(animated: false, completion: nil)
}
When you present nextPageCon and then navigate away by selecting a different tab, this func will trigger and dismiss itself.
I have 3 ViewController : LoginViewController, CheckinViewController, & ProfileViewController
The flow is :
LoginVC --> CheckinVC --> ProfileVC
What i need is:
I want to dismiss "ProfileVC" & "CheckinVC" when click logout button in "ProfileVC" then go back to the "LoginVC"
LoginVC.swift
let checkinViewController = self.storyboard?.instantiateViewController(withIdentifier: "CheckinViewController") as! CheckinViewController
self.navigationController?.pushViewController(checkinViewController, animated: true)
JustHUD.shared.hide()
self.dismiss(animated: false, completion: nil)
CheckinVC.swift
if let profileView = self.storyboard?.instantiateViewController(withIdentifier: "ProfileViewController") {
profileView.providesPresentationContextTransitionStyle = true
profileView.definesPresentationContext = true
profileView.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext;
// profileView.view.backgroundColor = UIColor.init(white: 0.4, alpha: 0.8)
profileView.view.backgroundColor = UIColor.clear
profileView.view.isOpaque = false
self.present(profileView, animated: true, completion: nil)
Here is i'm trying to do
ProfileVC.swift
#IBAction func clickLogout(_ sender: Any) {
UserDefaults.standard.removePersistentDomain(forName: Bundle.main.bundleIdentifier!)
UserDefaults.standard.synchronize()
self.dismiss(animated: false, completion: {
print("ProfileView : dismiss completed")
let loginViewController = self.storyboard?.instantiateViewController(withIdentifier: "LoginViewController") as! LoginViewController
self.navigationController?.pushViewController(loginViewController, animated: true)
self.dismiss(animated: false, completion: {
print("SUCCESS")
})
})
}
Well you need to do an Unwind Segue so you can go back in your LoginVC.
Follow these simple four steps to create Unwind segues:
In the view controller you are trying to go back to, LoginVC in your example, write this code:
#IBAction func unwindToVC1(segue:UIStoryboardSegue) { }
( Remember: It’s important to insert this method in the view
controller you are trying to go back TO! )
In the Storyboard, go to the screen you’re trying to unwind from ( ProfileVC in our case ), and control + drag the viewController icon to the Exit icon located on top.
3. Go to the document outline of the selected viewController in the Storyboard, select the unwind segue as shown below.
Now, go to the Attributes Inspector in the Utilities Pane and name the identifier of the unwind segue.
Finally, write this code where you want the unwind segue action to be triggered, ProfileVC in our case.
#IBAction func clickLogout(_ sender: Any) {
UserDefaults.standard.removePersistentDomain(forName: Bundle.main.bundleIdentifier!)
UserDefaults.standard.synchronize()
performSegue(withIdentifier: "unwindSegueToVC1", sender: self)
}
For more information check Create Unwind Segues
While Enea Dume's solution is correct if you want to use storyboards, here is the explanation of the problem, and the solution if you want to do it in code like you have been so far.
The Issue
If we focus on the self.dismiss calls in the logoutFunction in ProfileVC, this is what happens.
The first time you call self.dismiss, ProfileVC will dismiss itself and be removed from the view stack.
In the completion delegate, you are pushing a new LoginVC to a navigation controller. However, the CheckIN VC is presented over the navigation controller so you can't see anything happen.
The second call to self.dismiss does nothing as ProfileVC is not presenting any other view controllers and it is not in the stack any longer.
The Solution
You need to keep a reference to LoginVC that presented the CheckInVC. If you call "reference to LoginVC".dismiss, it will dismiss the view controllers above it in the stack and take you back to the login view controller.
In the class CheckinVC.swift, in the function viewDidAppear, check if the user is still active or not based on the session that you are maintaining and the pop to login view controller accordingly. If user status is logged out, then it will go to login view controller. Else it will work as usual.
Problem is that you are trying to dismiss twice ProfileVC but what you actually need is to dismiss it and then pop CheckinVC.
Also after dismissing a view controller it no longer has a reference to the NavigationController so you need a reference to it in a temporal variable.
Change ProfileVC like this:
#IBAction func clickLogout(_ sender: Any) {
UserDefaults.standard.removePersistentDomain(forName: Bundle.main.bundleIdentifier!)
UserDefaults.standard.synchronize()
let navigationController = self.navigationController
let loginViewController = storyboard?.instantiateViewController(withIdentifier: "LoginViewController") as! LoginViewController
self.dismiss(animated: false, completion: {
print("ProfileView : dismiss completed")
navigationController?.pushViewController(loginViewController, animated: true)
navigationController?.popViewController(animated: false)
})
}
I have ViewController1 and ViewController2 . When i click a button on the ViewController1 should go to ViewController2 and when press a custom back button should return to ViewController1 without reloading its content for ex:- if i type something on ViewController1's text filed it should remain as it is.
Does anyone knows any solution for this?
viewcontoller1 button click code...
#IBAction func Parsent(sender: AnyObject) {
let secondVC = self.storyboard?.instantiateViewController(withIdentifier: "Identifier" as! ViewController2
let navigationVC = UINavigationController(rootViewController: secondVC)
self.present(navigationVC, animated: true, completion: nil)
}
ViewController2 button code here..
#IBAction func Dismiss(sender: AnyObject) {
self.dismissViewControllerAnimated(true, completion: nil)
}
1- Load View Controller 1
2- Your custom button should present ViewController 2 on top of view controller 1 (the native self.present does this, note that it present it on top of VC1 so VC1 is still there)
3- your back button on View Controller 2 dismisses View Controller 2 and you return to View Controller 1 the same as you left it
Hope this helps!
In my swift app I have a UIViewController with a button. This button opens up the UIViewController number 2 and there user has another button. When user presses it - he opens UIViewController number 3. There is also a button and when user presses it - he calls the code:
self.dismissViewControllerAnimated(false, completion: nil)
and thanks to it the UIViewController number 3 disappears and user sees UIViewController number 2. My question is - is there a way of also dismissing the UIViewController number 2 so that user can come back smoothly from number 3 to number 1?
For now I created a function and call it through protocol:
UIViewController number 2:
protocol HandleYourFullRequest: class {
func hideContainer()
}
class FullRequest: UIViewController, HandleYourFullRequest{
func hideContainer(){
self.dismissViewControllerAnimated(false, completion: nil)
}
#IBAction func exitbuttonaction(sender: AnyObject) {
self.performSegueWithIdentifier("temporarySegue", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "temporarySegue"){
if let fullRequestDetails = segue.destinationViewController as? YourFullRequest
{
fullRequestDetails.delegateRequest = self
}
}
}
}
UIViewController number 3:
class YourFullRequest: UIViewController{
var delegateRequest:HandleYourFullRequest?
#IBAction func exitbuttonaction(sender: AnyObject) {
self.dismissViewControllerAnimated(true, completion: nil)
delegateRequest?.hideContainer()
}
}
But with that solution when user presses the button - the UIViewController number 3 disappears and UIViewController number 2 appears for a second and disappears then. Is there a way of removing number 2 without showing it to the user and point him directly to the number 1?
I'm still unclear as two which button is wired to which action, but from what I can tell when the dismiss button is pressed on view controller 3 it calls self.dismissViewControllerAnimated(false, completion: nil) in view controller number 2.
Try putting this method in view controller 3.
#IBAction func exitButtonAction(sender: AnyObject) {
self.presentingViewController?.presentingViewController?.dismissViewControllerAnimated(true, completion: nil);
}
This will work assuming that both view controllers are presented and not pushed in something like a navigation controller.
You can use removeLast() function to pop controllers off the stack.
#IBAction func doneAction(sender: AnyObject) {
var vc = self.navigationController?.viewControllers
// remove controllers from the stack
vc?.removeLast()
vc?.removeLast()
// Jump back to the controller you want.
self.navigationController?.setViewControllers(vc!, animated: false)
}
You can use popToViewController(viewController: UIViewController, animated: Bool)
Where viewController is the viewController you wish to pop to, in your case, 'UIViewController number 1'.
popToViewController Documentation
If you don't have a reference to the View Controller, you can get it from self.navigationController.viewControllers, it will be the first object in your example.
There is a method on UINavigationController called setViewControllers. It takes an array of all the view controllers you want active. You can get all the view controllers on the stack as an array, remove the ones you don't want, then call setViewControllers with the updated array.
My first view controller has a button, which triggers the #IBAction goTo2ndVc() which presents a second ViewController:
class FirstVC: UIViewController {
...
#IBAction func goTo2ndVc() {
let secondVc = SecondVC(label: "I am second vc.")
self.presentViewController(secondVc, animated: true, completion: nil)
}
When the button is pressed, the 2nd view controller is shown on screen. No problem.
In 2nd view controller, there is also a button which is used to go back to 1st view controller:
class SecondVC: UIViewController {
...
#IBAction func backToFirst(sender: AnyObject) {
print("go back ...")
self.navigationController?.popViewControllerAnimated(true)
}
}
I looked on internet, people suggest to use navigationController?.popViewControllerAnimated(true) to go back to previous controller. But when I press the go back button I can see the print message "go back ..." but the app doesn't go back to 1st view controller. WHY?
#IBAction func backToFirst(sender: AnyObject) {
print("go back ...")
self.dismissViewControllerAnimated(true, completion: nil)
}
In Swift 3
self.dismiss(animated: true, completion: nil)
you should not use navigation controller, because you didn't use it when you were adding the second view controller. that's why simply call dismissViewControllerAnimated method.
You have to use UINavigationController and its pop methods only when you add your view controllers via pushViewController method.
Familiarize yourself with the concept of navigation controller here: https://developer.apple.com/library/ios/documentation/WindowsViews/Conceptual/ViewControllerCatalog/Chapters/NavigationControllers.html
there
the issue is very simple..
self.presentViewController(secondVc, animated: true, completion: nil)
the code will present second view, you are not pushing it.
self.navigationController?.popViewControllerAnimated(true)
the popViewController will pop back to the previous view controller from where it is been pushed.
So, there are two ways you can achieve what you want
1)If you want to present viewController then you have to dismiss the view controller to show previous view controller with
self.dismissViewControllerAnimated(true, completion: nil)
2)If you want to use PopToVewcontroller, then you have to push you second view controller instead of presenting it with
self.navigatioVonroller?.pushViewController(secondVc, animated: true)
If you want to return to the previous view controller, you can simply add:
[self dismissViewControllerAnimated:YES completion:nil];
to the button action method.
If this is added on the nav view controller present on every screen, I see no reason why it shouldn't work as it would always dismiss the most recently presented view.