How to dismiss VIewController iOS Swift - ios

I am new to iOS development. I am developing an application using iOS Swift. I have 3 view controllers viewController1, viewController2, viewController3.
When I click from viewController1 its move to viewController2. By using the following code
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let secondViewController = storyboard.instantiateViewControllerWithIdentifier("viewController2")
presentViewController(secondViewController, animated: false, completion: nil)
Now I am moving from viewController2 to viewController3 by using the following code
performSegueWithIdentifier("viewController3", sender: scoreColorArray);
It's all fine. Now I want to back from viewController3 to viewController1. My problem it is not going to viewController1 it is going to viewController2. I know the reason viewController2 not dismissed.
I want to dismiss the current view controller and start new one. How can I do it? I know there is some ways to do it, please someone help me to finds the issue.

Since your presentation sequence is VC1 -> VC2 -> VC3 you need to call self.presentingViewController?.presentingViewController?.dismissViewControllerA‌​animated on VC3, traversing this way your sequence in reverse.

You can achieve it by using delegate.
You send delegate call from controller 2 to controller 1 for dismiss
controller 2.
After dismiss success, you will push controller 3 from controller 1
You can look my demo for this case: Demo Pushview

Related

Swift - Shake gesture dismisses the child view controller

I have two view controllers which are defined in storyboard as,
UIViewController -> (Show Detail Segue) -> UITabBarController
My problem is; I am using a library called netfox to debug my HTTP requests. And this librarie's UI is being triggered by Shake Gesture. But when I come to the UITabBarController Shake Gesture on the simulator does not work at first time. At the second time it dismisses the ViewController that is currently on the screen and obviously a child of UITabBarController and goes back to the initial UIViewController. This is exactly like connecting two ViewControllers with modal segue and calling self.dismiss() from the child one.
I tried to change rootViewController of the UIApplication by,
UIApplication.shared.keyWindow.rootViewController = self
in the viewDidLoad() method of the UITabBarController and it worked. However, for this solution, the items(buttons, titles) in the UINavigationBar of any UINavigationController that is the child of UITabBarController are missing.
I have no idea why this is happening. If someone helps me while I am solving this, I would be really appreciated.
Instead of using
self.performSegue(withIdentifier:_)
calling this in the UIViewController have worked:
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let viewController = mainStoryboard.instantiateViewControllerWithIdentifier("tabBarcontroller") as UITabBarController
UIApplication.sharedApplication().keyWindow?.rootViewController = viewController;
Respect to this answer.

Unwind segues with programmatically created view controllers

I have a view controller (PhotoViewController) which has a child view controller (CameraViewController). In CameraViewController, there is a button that sets off a chain of segueing through other programmatically created view controllers. On the last of these view controllers, I want to unwind to the original PhotoViewController. All examples I have found require you to have view controllers in the storyboard, which I don't have. How can I do this?
You have not understood what an unwind segue is. It is merely a way of reversing the calls that created the current view controller and got it into the view controller hierarchy, in the special case where you want to trigger this through a segue in a storyboard.
For example, if you (or the storyboard) called pushViewController (for a pushed view controller), an unwind segue is just a way of calling popViewController.
Or, if you called (or the storyboard) called present (for a modally presented view controller), an unwind segue is just a way of calling dismiss.
If you don't have your view controllers in a storyboard, you don't need an unwind segue; you just do one of those two things, directly, in code.
Remember, we all got along for years just fine without unwind segues. In fact, we all got along for years without storyboards! And so can you.
If your original PhotoViewController is created on a storyboard and you want to segue back to it from a programmatically made VC you have present it rather than unwinding because unwindSegues are for storyboards only.
To present your PhotoViewController here is one of the ways to do so.
func presentPhotoViewController() {
let storyboard = UIStoryboard(name: "YourStoryBoardName", bundle: nil)
if let photoViewController = storyboard.instantiateViewController(withIdentifier: "PhotoViewControllerUniqueId") as? PhotoViewController {
// Pass any data you have (Optional)
self.present(photoViewController, animated: true, completion: nil)
// If your PhotoViewController is embeded in a navigation Controller do the following.
//let navController = UINavigationController(rootViewController: photoViewController)
//self.present(navController, animated: true, completion: nil)
}
}

SWIFT 3: Segue with navigation controller

I'm trying to send some values from one viewcontroller to another. (all embedded in NavigationController). I could make segue with normals viewcontrollers so in general I understand a segue idea. I've to do that in two different ways and got two different problems.
First way, segue does right but "two times". I mean after segue (which I want) there is another segue to same controller but without navigation controller and without data I would send. The "back" button on last viewcontroller is returning to AlmostViewController.
Here's code:
Second way, Nothing happened,
ErorCould not cast value of type 'RevisionApp.AlmostViewController'
(0x1055d58c0) to 'UINavigationController' (0x107669f18).
Here's code:
For the first Problem, When using embedded in navigation controller you have don't have to create action function when the button is tapped. Navigation controller does it for you. So things you need to do :
Disconnect the function btnTapped from the button using storyBoard.
Delete or comment the function btnTapped(You don't need it).
Problem is line number 18. You are trying to cast AlmostViewController to a UINavigationController. Directly access like this,
let detailController = segue.destination as! AlmostViewController
let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let nextViewController = storyBoard.instantiateViewControllerWithIdentifier("ViewController2") as NextViewController
self.presentViewController(nextViewController, animated:true, completion:nil)

Unable to go back through a navigation controller to a VC of another navigation controller using Swift

As you can see below, the notificationsVC is a part of the TabBarController which is embedded in a navigationContoller(lets call it first nC). Then theres a segue from notificationsVC to the second navigationController which will show the messagesVC.
There's a back button in messagesVC which when pressed should go back to notificationsVC
func backbutton() {
navigationController?.popViewControllerAnimated(true)
}
Now this is obviously not working because the navigationController will get the nearest NC and pop the VC in its stack but it won't let me go back to the notificationsVC.
Any other alternative?, although I've tried this with no success as well.
self.dismissViewControllerAnimated(true, completion: nil);
More detailed view
Also I'm using the JSQMessagesViewController library to show the messages in messagesVC which shouldn't matter but still worth mentioning. Thanks for your time!
You can access first NavigationViewController by asking it from TabBarViewController like in code below:
tabBarController?.navigationController?.popViewControllerAnimated(true)
Also asking navigation controller from you second navigation controller should work:
navigationController?.navigationController?.popViewControllerAnimated(true)
Your Navigation controller has only one VC i.e MessagesVc. So when you pop it,there is no other VC in the Navigation Controller's stack which can be presented. Your NotificationsVC is not in the Navigation controller's stack.
So I suggest you to do like this on back button click:
tabBarController?.selectedIndex = Index_Of_NotificationsVC
Try : -
let nVC = self.navigationController?.tabBarController?.navigationController?.storyboard?.instantiateViewControllerWithIdentifier("NotificationStoryboardVC_ID") as! NotificationVC
navigationController?.tabBarController?.navigationController?.pushViewController(nVC, animated: true)

Pass data with segue without displaying screen

I'm trying to achieve passing of data using segue, but without displaying the screen. There are two view controllers in my project and I will name them FirstViewController and SecondViewController.
On FirstViewController, I am using Show Adaptive Segue to pass data using performSegueWithIdentifier. The prepareForSegue method will be called, and recognising the identifier I've set to display SecondViewController.
However, the problem is I do not want to display SecondViewController. There are other things that my users may want to do before heading for SecondViewController.
I'm new to iOS programming, and I only know passing of data with segue. Please do share with me if there are methods to pass data apart from segue.
EDIT: To further elaborate my question. I'm working with TabBarController, and both View Controllers are accessible on the Tab bar. So when I am on SecondViewController with some data already "segue-ed" over from FirstViewController, I can head back to FirstViewController to add more data. At SecondViewController with UIRefreshControl I need the updated data.
If you do the segue in code you can do what you want in a following way
1) Instantiate view controller from the story board
let storyboard: UIStoryboard = UIStoryboard(name: "SecondViewController", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("set_it_in_IB") as! SecondViewController
2) Set the properties you need to set as the view controller is already instantiated
vc.someProperty = "asd"
3) Segue!
viewController.presentViewController(viewControllerToPresent: UIViewController, animated: Bool, completion: (() -> Void)?)
Hope that helps!
From your user's perspective, they would not know whether the data is being updated before they segue or not, so it is probably fine to just pass the data with the prepareFoSegue function.
Otherwise, you could try setting a notification to the viewDidLoad on your FirstViewControllerand SecondViewController by
NSNotificationCenter.defaultCenter().addObserver(self, selector: nil, name: updateSecondVCNotification, object: nil)
and posting the notification from the FirstViewController whenever the data needs to be updated using the
NSNotificationCenter.defaultCenter().postNotificationName(updateSecondVCNotification, object: self)
Then on second view controller set the the selector of the addObserver to a string of the name of whatever function you want it to do like "reloadNewData"
func reloadNewData() {
tableView.reloadData()
}
Does this help? Don't forget to set the updateSecondVCNotification as a global string constant at the top of your FirstViewController. Learn more about NSNotificationCenter at https://www.andrewcbancroft.com/2014/10/08/fundamentals-of-nsnotificationcenter-in-swift/
Woo! Notifications! \(^▽^)/
I'm not sure if that would work for you, but you could simply keep the data in memory of your FirstViewController for the time during which the user is still interacting and giving feedback and once it's done, send all the data to the SecondViewController through the segue.

Resources