I have a secondary ViewController that appears programmatically via a Storyboard segue:
func actioncall ()
{
performSegue(withIdentifier: "showIgnoreVC", sender: self)
}
)
This function is part of the main ViewController, and is called via an NSNotification from the AppDelegate, which in turn is triggered by a Menu Item click.
However, even though the segue is connected to the main ViewController, the following code does not dismiss the secondary view:
#IBAction func dismiss(_ sender: Any)
{
print("Hello? Gonna close?")
self.presenting?.dismissViewController(self)
}
There are no errors, the function is called upon the correct Dismiss button click, but the secondary view does not dismiss. I have tried every variation of dismissViewController to no avail.
When I use a button on the Main view to activate the same segue, everything works as it is supposed to. I simply do not wish to clutter up the main View with a bunch of buttons.
Any ideas are appreciated, thank you very much.
dismissViewController works only for view controllers, that were presented modally (using Present Modally Segue)
As said in the answer to this SO question, you should dismiss view controllers, presented by Show Segue, like this:
navigationController?.popViewController(animated: true)
dismiss(animated: true, completion: nil)
Related
I have a storyboard with two view controllers. First one, VC_1, has one button that opens 2nd one - VC_2.
VC_2 also has a button that opens VC_1.
Both controllers have almost identical code:
class VC_1: UIViewController
{
override func viewDidLoad()
{
super.viewDidLoad()
print(“VC_1 loaded")
}
override func viewDidAppear(_ animated: Bool){ print(“VC_1 appeared") }
override func viewDidDisappear(_ animated: Bool){ print(“VC_1 disappeared") }
#IBAction func btnShowVC_2(_ sender: UIButton)
{
let storyboard = UIStoryboard(name: "Main", bundle: nil)
secondVC = storyboard.instantiateViewController(identifier: “VC_2”)
secondVC.modalPresentationStyle = .fullScreen
show(secondVC, sender: self)
}
}
The difference is only in "VC_2" instead of "VC_1" in the 2nd controller code.
I have seen this View Controller creation code in Apple documentation and many other examples around the Internet.
When I press the button on the VC_1, I see in the debug window, that VC_2 is loaded and appeared, and VC_1 is disappeared. And same, of course, happens when I press the button on VC_2 - it disappears, and VC_1 is loaded again.
My questions are:
what happens with View Controller object after "viewDidDisappear" has been called? Does it really disappear from memory, or "disappear" only means "you cannot see it on the screen?". I do not see "viewDidUnload" in the documentation...
I suppose that "viewDidLoad" means that new View Controller object was created in memory. Is there any way to load the View Controller object only once, and then hide and show it without causing "viewDidLoad" to be called? I tried to do it with global variable "secondVC" but got "Application tried to present modally an active controller" error.
viewDidDisappear: called after the view is removed from the windows’
view hierarchy. No, View controller object just left the view property. By the way the amount of memory used by view controllers is negligible. So dont think about too much. If you want to catch when Your View controller object release from the memory put
deinit { print("vc deallocated") }
viewDidUnload, it has been deprecated since the iOS
6, which used to do some final cleaning.
Partly true. Keep in mind ViewDidload called one time for the life cycle of view controller. There is a method called before viewdidload but this is not related with your question.
In addition to "There is a method before viewdidload" -> loadView( ) is a method managed by the viewController. The viewController calls it when its current view is nil. loadView( ) basically takes a view (that you create) and sets it to the viewController’s view (superview).
It's easier to show you a drawing and then explain.
Dashboard Storyboard
I have 2 separate UIViewControllers (i've included just one in the drawing, the other is irrelevant) embedded in container view called ContainerViewController.
Post Storyboard
NewPostViewController shows a UIButton that presents TextPostViewController. As you can see, all of them are embedded in UINavigationControllers. Now, once the completion block of the new post is being called, I have to present the ContainerViewController and it needs to handle it's own logic. The problem is that it's embedded in UINavigationController and once I present it, the UITaBbar is hidden.
I tried to do this:
self.performSegue(withIdentifier: "TextPostToNavContainerVC", sender: nil)
The transition is successful but I'm losing the UITabBar, even though in the DashboardViewController and the ContainerViewController I called:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
tabBarController?.tabBar.isHidden = false
}
What am I doing wrong or is there are better way to do that?
You should instantiate the tab bar controller. not the view controller.
Imagine you're putting a initial view controller ahead of your tab bar controller. Making your tab bar not being pushed
If I undestand it correctly.
You are doing this
Segue connect to a view controller
But you should actually do this Segue connected to a tab bar controller
You can try to add it as a child to control it's frame like this
let textPost = self.storyboard?.instantiateViewController(withIdentifier: "containerID") as! TextPostToNavContainerVC
textPost.view.frame = CGRect(x:20,y:0,width:self.view.frame.width,height:self.view.frame.height-50)
self.view.addSubview(nvc.view)
self.addChildViewController(textPost)
textPost.didMove(toParentViewController: self)
Im building an app in swift for macOS, and I have a button on my initial view controller that I want to display a different view controller. I ctrl dragged from that button to the new view controller, and all of the segue options display the new view controller as a new window, rather that replacing the initial view. How can I make this button transition view controllers similar to how it works in iOS apps?
You can first make your segue to the 2nd view controller and then create an IBAction from your button where you call
self.dismiss(animated: true, completion: {})
within it. By doing this your initial view controller will no longer exist.
More detailed:
Segue from your button to the second view controller (ctrl drag)
Make an IBAction by ctrl drag from your button to the view controllers code
Put this into your IBAction:
self.dismiss(animated: true, completion: {})
Now it should look something like this:
#IBAction func dismissView(_ sender: Any) {
self.dismiss(animated: true, completion: {})
}
By clicking on your button your application go to the next view controller and the initial view controller will be dismissed.
i'm fairly new to swift and having some difficulty with unwind segues in a master detail application.
the unwind seems to work fine dismissing my popovers on the iPhone, however when i try the same thing on the iPad, the popover remains.
If i add a dismissViewControllerAnimated to the presenting viewController's unwind handling action, then the iPad version works fine and dismisses the popover, however the iPhone version dismisses the popover and then dismisses the view that presented the popover. i.e. dismisses two views.
I have worked out that the problem is that popover's are automatically dismissed with an unwind when presented modally such as on an iPhone. However when presented as true popovers they don't dismiss with an unwind segue. Could somebody help me figure out how to manage both cases so that only the popover will be dismissed. Thank you very much in advance.
Okay. after a long time working on this i managed to come up with a solution. i used a popoverpresentationcontroller and declared the presenting controller as the delegate. by then adding an additional function forcing the iPhone to use the popover in lieu of the modal presentation, the presentation and dismissal is consistent for the iPhone and iPad. the code is below. I just used a generic UIViewController in the if let vc statement so that I could use this with a popover that's imbedded in a navigation controller also.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let identifier = segue.identifier {
switch identifier {
case "My Segue Identifier" :
if let vc = segue.destinationViewController as? UIViewController {
if let ppc = vc.popoverPresentationController {
ppc.delegate = self
}
}
default: break
}
}
}
additionally you need to add the following function to prevent the modal presentation on the iPhone:
func adaptivePresentationStyleForPresentationController (controller:UIPresentationController)-> UIModalPresentationStyle {
return UIModalPresentationStyle.None
}
In my app I have a "home" screen from which I can present a hamburger menu (coded as a modal transition in Storyboard).
The menu is a UITableView where a user will select a row. The menu has a delegate method which calls the following function in the presenting screen (my "home" screen)
// Menu delegate method
func menuDidExit(menuVC:MenuVC) {
self.dismissViewControllerAnimated(true, completion: {
// After dismissal of menu, call the chosen option
if let selectedOption = menuVC.menuSelection {
self.performSegueWithIdentifier(menuVC.menuSelection?.rawValue, sender: self)
}
})
}
This function will both dismiss the menu view controller, and then (once that transition is complete), present a second view controller based upon the chosen menu option, using the "performSegueWithIdentifier" command.
The issue that I have is that while the menu dismiss works fine (the menu slides off screen gracefully) - there is no animation for the presentation of the next view controller - it simply appears on screen after the menu has been dismissed.
I can call the desired view controller via a button/segue, and all works well, however when it is part of the completion block above it fails to animate the transition. This leads me to believe that there is something fundamentally wrong with my approach - hence the question, what is the correct way to push a second view controller after handling the dismissal of the first.
Many thanks for any suggestions
I think you can use this:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
self.dismiss(animated: true) {
//dismiss your menu here
}
}
Hope it can help you.
Please let me know if it not work.
Thanks