I'm using segue navigation with self.perfomSegueWithIndentifier function with type of show segues.I noticed after every navigation other view/viewcontroller did not remove from RAM.What I have to do to solve this
This is what you are looking for:
On Button Tap on View Controller 1:
self.navigationController.pushViewController(secondViewController, animated: true)
On Button Tap on View Controller 2:
self.navigationController?.popViewControllerAnimated(true)
Programmatically
Lets say you have VC1 embed in UINavigationController for now VC1 becomes the top view controller on the navigation stack.
So if you are going VC1 -> VC2
self.navigationController?.pushViewController(vc2, animated: true)
In that case VC2 becomes the top view controller on the navigation stack.
and while coming back from VC2 -> VC1 (Button tap on VC2 perform this statement)
self.navigationController?.popViewControllerAnimated(true)
In that case again VC1 becomes the top view controller on the navigation stack.
Using Segue
Just use Show(e.g Push) and set the identifier for that like i have pushView
and invoke
self.performSegueWithIdentifier("pushView", sender: nil) for moving VC1 -> VC2
and for coming back to VC2 -> VC1
use the same self.navigationController?.popViewControllerAnimated(true)
Related
I have inherited a navigation controller issue in an existing app that I'm trying to solve cleanly.
This app has multiple storyboards and multiple UINavigationControllers. At one point in the app, a series of view controllers is presented modally, using a separate storyboard and a separate nav controller. When the modal process is complete, the navigation hierarchy looks something like this:
NavController1 -> VC1 ['Present Modally' segue] -> NavController2 -> VC2 -> VC3 -> VC4
When the user completes the modal activity in VC4, dismiss() is called programmatically on VC4 and the user can then navigate back to VC1 using the back button.
However, what we really need to do is to 'pop off' all of the modally presented set of view controllers (and their nav controller) when the user finishes the modal activity. The problem is that from VC3 or VC4 I can't call popToRootViewController(). I also can't traverse down the VC stack to find VC1, since the current Nav controller doesn't manage it.
A couple solutions come to mind:
1) use the notification manager and have VC1 listen for the message to pop everything off back to itself
2) pass a reference to VC1 as a delegate all the way up the chain so that VC3 or 4 can have it pop everything off
Both of these solutions follow the general maxim that the presenting VC should be the one that dismisses, but neither are what I would consider clean.
I would welcome any thoughts or alternative solutions.
Assuming that these are the way the view controllers were laid out:
NavController1 --['Root View Controller' segue]--> VC1 --['Present Modally' segue]--
--> NavController2 --['Root View Controller' segue]--> VC2 --['Push' segue]--> VC3 --['Push' segue]--> VC4
You should be able to go back to VC1 by dismissing either VC2, VC3 or VC4.
// example for vc4
vc4.navigationController?.dismiss(animated: true, completion: nil)
However, if each of the viewControllers were presented modally, you should be able to traverse through the presentingViewController to reach VC1.
var currentVC: UIViewController? = self
var presentingVC: UIViewController? = currentVC?.presentingViewController
while presentingVC != nil && !(presentingVC is VC1) {
currentVC?.dismiss(animated: true, completion: nil)
currentVC = presentingVC
presentingVC = currentVC?.presentingViewController
}
Hope that helps.
When popping, you may kick out the viewControllers from your navigation Controller, would solve your problem
extension UINavigationController {
public func removeViewController(classes : [String]) {
var vcs = [UIViewControllers]()
for viewController in self.viewControllers {
let name = viewController.className
if !classes.contains(name) {
vcs.append(viewController)
}
}
if classes.count < vcs.count {
self.viewControllers = vcs
}
}
}
now think you have 4 viewControllers , A, B, C, D, you want to remove B and C and Move Back To A
In D's View Controller
override func viewDidLoad() {
super.viewDidLoad()
//your works
let viewControllersToRemove = [String(describing: type(of:B)), String(describing: type(of:C))]
navigationController.removeViewControoler(classes : viewControllersToRemove)
}
VC1 = Table View
VC2 = New VC
So I'm using A segue to show VC2 from VC1. When using the segue, VC2 shows coming from the bottom of the screen and covering up VC1. When I go back from VC2 to VC1, VC1 does the same animation.
What I was wondering is, is there any way to reverse the back segue from VC2 to VC1 so either VC2 looks as though it is going downwards or VC1 is coming over it from the top of the screen.
Thanks,
Riley
This push effect animation does present modally segue with destination ViewController's transition style Cover Vertical
So when you want to go back from VC 2 to VC 1 with animation opposite to push effect, you can do it just by dismissing VC 2. You don't have to use any segue, just dismiss ViewController.
So from VC 1 you can go to VC 2 by performing segue (you've already done that)
performSegue(withIdentifier: "identifier", sender: self)
and then from VC 2 you can go back to VC 1 by dismissing VC 2
dismiss(animated: true, completion: nil)
I currently have parental "menu" TableView with UINavigationBar and from each cell there is a segues by reference outlet to 3 similar Views with different information.
In each View there is a buttons to other 2 Views.
With every button's segue opens another View.
The problem:
From every View UINavigationBar's back button returns me to previous View but i tries to make back button to "menu".
Additional Bar Button Item and segue from it makes very close effect but segue animation is not like in UINavigationController.
How I could clean UINavigationBar transitions history in segue to initial View?
You can try pop to root view controller or You can edit navigation controller viewControllers property and remove/add some VC in between.
You can try Unwind Segue mechanism too.
Here are some methods(function) that navigation controller providing for pop operations. They are returning optional UIViewController (intance) from it’s navigation stack, that is popped.
open func popViewController(animated: Bool) -> UIViewController? // Returns the popped controller.
open func popToViewController(_ viewController: UIViewController, animated: Bool) -> [UIViewController]? // Pops view controllers until the one specified is on top. Returns the popped controllers.
open func popToRootViewController(animated: Bool) -> [UIViewController]?
Here is sample code as a solution to your query::
// if you want to back to root of your app
if let rootNavigationController = self.window?.rootViewController as? UINavigationController {
rootNavigationController.popToRootViewControllerAnimated(true)
}
// But if you want to back to root of your current navigation
if let viewcontroller = self.storyboard?.instantiateViewController(withIdentifier: "NewViewController") as? NewViewController { // or instantiate view controller using any other method
viewcontroller.navigationController?.popToRootViewControllerAnimated(true)
}
Let's say that on my regular flow I have
VC1 -> VC2 -> VC3 -> VC4
But I have a requirement that when I touch a special button on VC1 it needs to go to VC4.
No problem there. The problem is that when I tap the back button on VC4, it needs to go back to VC3 instead of VC1.
I already tried pushing From VC1 -> VC2 and VC2 -> VC3 without animation and then VC3 -> VC4 with animation, but you can see a quick glimpse of VC3 which looks awful.
Any ideas?
I think in this specific case, you can insert a view controller on the navigation controllers stack after presenting the 4th viewController
if let navigationController = navigationController {
navigationController.pushViewController(vc4, animated: true)
let vc3Index = navigationController.viewControllers.count - 1
navigationController.viewControllers.insert(vc3, atIndex: vc3Index)
}
This should place VC3 next in line when the user presses back from VC4. Untested code, btw.
You can modify the UINavCon's viewControllers to achieve the order you want.
func specialButtonInVc1() {
self.navigationController?.pushViewController(fourth, animated: true)
self.navigationController?.viewControllers = [self, second, third,fourth]
}
I have a view controller VC1 that is presented modally over full screen from some other VC0. In my storyboard I have a modal segue from VC1 to VC2 also presenting over full screen. When in my app I can plainly see VC2 over VC1 over VC0, because some parts of their views are transparent. Perfect.
However, I'm going to reuse VC2 many times so I don't want to have a segue to it for each controller in my storyboard, so I want to accomplish this same thing programmatically. However, when I call presentViewController:animated:completion in VC1 to present VC2, the view of VC1 disappears when the modal transition is complete. When VC2 is dismissed, the view of VC1 reappears when the transition animation is complete.
How can I get the same effect programmatically as when I'm using the storyboard segue?
let newView = self.storyboard!.instantiateViewControllerWithIdentifier("NewViewController") as! NewViewController
newView.modalPresentationStyle = UIModalPresentationStyle.OverFullScreen
self.presentViewController(newView, animated: true, completion: nil)
You can only present on a visible controller, which is usually the rootViewController. But when there is a modally-presented controller, it covers the root controller, so you can't use that. But you can present on the modal, which is accessed though rootViewController.prsentedViewController. Here's some code:
let rootVC = window?.rootViewController
let presentingVC = (rootVC?.presentedViewController ?? rootVC)
presentingVC?.present(myController, animated: true, completion: nil)
You don't need to change the modalPresentationStyle.
You need to set the modalPresentationStyle property of the presented controller to UIModalPresentationOverFullScreen. Set that property just before you call presentViewController:animated:completion.