View Controller get stuck on calling unwind segue in Swift - ios

I have a bit complex hierarchy of calling multiple VC's and then at the end unwind to particular VC again, My flow is like this,
I have a VC that opens with these two conditions,
HomeVC -> DetailVC -> VC1 -> An API call to check if data exist, if yes then present ListVC if not then present Form VC
If FormVC is opened then after submitting form i have to show ListVC
If ListVC is opened first then it simply present Form VC, as in UI ListVC comes first and FormVC is the second one.
Now when i comes directly from FormVC to DetailVCthrough unwind segue, detail vc screen get stuck, now action is performed on it neither it scrolls. I'm too much confused why it is showing such behaviour. How i can fix it? why it is stuck my app?
This is how i call Unwind segue in DetailVC,
#IBAction func unwindToPropertyDetail(sender: UIStoryboardSegue)
{
}
and in FormVC, I just performSegue method like this to come on DetailVC,
self.performSegue(withIdentifier: "GoToDetails", sender: self)

Have you try using dispatch queue?

Related

How to pop back to a TableViewController?

I start of with a tableViewController that has a list of names. When the user taps on a name, they are segued to a view controller.
While in that viewController the user may press a button that will take them to another table view Controller.
The layout is like this:
TableViewController(1) -> ViewController -> TableViewController(2)
My question is, how can I pop back to the first TableViewController from the Second TableViewController.
My rootViewController is my signIn View controller so I cannot pop back to root.
You can run this to pop to your rootViewController:
self.navigationController?.popToRootViewController(animated: true)
Update:
Since your rootViewController is not where you want to end up then you can iterate through your controllers and pop to a specific one:
for controller in self.navigationController!.viewControllers {
if controller.isKind(of: TableViewControllerOne.self) {
self.navigationController!.popToViewController(controller, animated: true)
break
}
}
Instead of TableViewControllerOne.self update to your desired controller.
If you're familiar with segues, you can implement an unwind segue. That would give you the added benefit of passing information back to TableViewController(1) if you needed to. To make that work in TableViewController1 you would add some code that looked like:
#IBAction func unwind(fromTableVC2 segue: UIStoryboardSegue) {
if (segue.source is TableVC2) {
if let svc = segue.source as? TableVC2 {
// pass information back
}
}
}
Then in your storyboard you would go to where you have your TableVC2 and drag the yellow VC circle to the exit and choose the function we created above. Name the segue (for this example we'll call it "UnwindToTableVC1"), and then somewhere in TableVC2 add the code:
func setVariableToPassBack () {
// Set up variables you want to pass back
performSegue(withIdentifier: "UnwindToTableVC1", sender: self) }
And that will take you back to your chosen destination with any information you wanted to pass back.
If you don't want to pass anything back, you really just need call the below line in your TableVC2:
performSegue(withIdentifier: "UnwindToTableVC1", sender: self)

How to navigate from popoverpresentation view controller to another view controller

I have a screen with a navigation controller and it has a button on the nav bar which displays a table (from another view controller) to select things from using pop over presentation, now on clicking any of those items i want to open another view controller a different screen.
BUT if i use navigationController?.pushViewController(tab, animated: true)
the new view controller is displayed within that small pop view itself
and if i use
navigationController?.presentViewController(tab, animated: true)
the navigation bar isn't there on that screen and i cannot go back to the previous screen. How to do it in such a way that i can go back to the screen which first displayed the pop Up list.
If you are using a Storyboard, it's really easy to do. If you're not, then you should. It's very good to use a Storyboard.
Let's call your view controllers these names:
The view controller that can show the popover is called SourceVC
The popover controller is called PopoverVC
The view controller to show when the user selects something from the table view is called NewVC
Add a show segue connecting your SourceVC to your NewVC. Give the segue an identifier.
Add an unwind segue that unwinds from PopoverVC to SourceVC. First, add these methods in your SourceVC:
func unwind(segue: UIStoryboardSegue) {
if let vc = segue.sourceViewController as? PopoverVC {
// get the thing that the user selected and store it somewhere
// perform a segue that shows NewVC
}
}
override func prepareForSegue(segue: UIStoryboardSegue) {
if let vc = segue.destinationViewController as? NewVC {
// pass the thing that the user selected to the NewVC
}
}
Then, select the PopoverVC and control drag it to the "Exit" thingy in SourceVC. And select "unwind:". Give this unwind segue an identifier as well.
When the user selects a row in the table view, just perform the unwind segue and store the thing that the user selected in a class-level variable so that you can pass it to SourceVC.

dismiss two controllers Swift

I have this situation :
I have a first view controller , when tap on button in it I open in modal mode another view controller , in this view controller when I tap another button I open in modal view another view controller and in it there is a button and when I tap on it I want to go to first view controller without re-initialize it.
How do I do it?
This is the perfect situation for an unwind segue.
Put this in your first viewController (the one you want to return to):
#IBAction func backFromVC3(_ segue: UIStoryboardSegue) {
print("We are back in VC1!")
}
Then in the Storyboard in your 3rd viewController, control-drag from your button to the exit icon at the top of the viewController and choose backFromVC3 from the pop-up.
Now, when the user presses the button in VC3, both VC3 and VC2 will be dismissed and you will return to VC1.
If you are not using Storyboards, you can dismiss the viewControllers with code. Here is code for a button's handler to dismiss two levels of viewController:
func doDismiss(_ sender: UIButton) {
// Use presentingViewController twice to go back two levels and call
// dismissViewController to dismiss both viewControllers.
self.presentingViewController?.presentingViewController?.dismiss(animated: true, completion: nil)
}
Thanks all for reply and edited my question :)
I found 2 line code to resolved my problem:
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
appDelegate.window!.rootViewController?.dismissViewControllerAnimated(true, completion: nil).
And that work well.
Thanks very much

How to completely close a view controller after returning to home view controller

I have an iOS app consists of three view controllers
homeViewController -> newGameSelectionViewController -> GameViewController
In GameViewController, I have a "home" button that should close the view controller and return to the newGameSelectionViewController.
In newGameSelectionViewController,
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
gameVC = segue.destinationViewController as! GameViewController
gameVC.countdown = 60
}
Then, I created an unwind segue to newGameSelectionViewController from GameViewController.
In newGameSelectionViewController,
#IBAction func unwindFromHomeButton(segue: UIStoryboardSegue) {
gameVC.dismissViewControllerAnimated(true, completion: nil)
}
When I press the home button in GameViewController, view closes and returns to the newGameSelectionViewController
The problem is, after pressing the home button and returning to the newGameSelectionViewController, countdown timer in GameView controller still continues. If I open an another GameViewController, it also open a completely new view controller. In another words, first GameViewController did not close by calling dismissViewController(). How do I close the ViewController completely so that if I start a new game, previous view controller does not continue counting at the background.
I am printing the countdown values with println() in GameViewController. Thats where I see the previous countdown values are still printing after dismissViewController()
Your gameVC variable will be holding a strong reference to the GameViewController instance, so even though it has been dismissed, the object still exists as its reference count is not 0.
You need to set gameVC to nil in your unwind method in order to remove this reference.
#IBAction func unwindFromHomeButton(segue: UIStoryboardSegue) {
gameVC=nil;
}
You don't need to dismiss the view controller explicitly in the unwind method if you are correctly invoking it via a segue - The unwind process will do this for you.

Unwind segue doesn't work SWIFT

I have a navigation controller, with a table view. When I press a cell, the detail view controller opens.
In my root view controller I have :
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "detailview" {
var destination:DetailViewController = segue.destinationViewController as DetailViewController
destination.delegate=self
}
}
In my detail view controller I have a back button :
#IBAction func back() {
self.navigationController?.popViewControllerAnimated(true)
}
The issue is, after 2 go to and return, my app crashes when I go back on the root view controller pressing back button. The console doesn't give me errors. It just crashes.
I think I have forgotten to unwind the segue.
So in my detail view controller I added :
#IBAction func unwindToViewController(segue: UIStoryboardSegue) {
println("unwind function")
}
I connect this function to my back button with "exit" in my storyboard.
When I run my app, If I press on the back button, the console doesn't display my print "unwind function", so unwindToViewController isn't called. Why ?
And my app still crashes...
Your unwindToViewController method should be placed in your root viewController, then ctrl-drag from the button in the detailViewController to the Exit icon in InterfaceBuilder. Choose that method in the popup menu.
Another approach would be to declare a protocol with a function in the rootViewController that is called from the detailViewController. You already set the rootViewController as the delegate of the detailViewController. Within that function you call dismissViewController.
Swift answer...
I had a similar problem.
The func: "segueForUnwindingToViewController(toViewController: UIViewController, fromViewController: UIViewController, identifier: String?) -> UIStoryboardSegue" was never called.
Solution:
since I didn't have a "UINavigationController", because I simply embeded the app in a Navigation Controller, I created a UINavigationController subclass for the Navigation Controller and added the function named above on it. Now the app calls "segueForUnwindingToViewController"

Resources