How to destroy instance of view controller after performing segue - swift

I use performSegueWithIdentifier to navigate between views controllers
I have a tableView with multiple rows, when a row is actioned, i call a webViewController to play selected ressource with segue
performSegueWithIdentifier("Play", sender: nil)
Associate with :
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if(segue.identifier == "Play") {
let detailVC = segue.destinationViewController as! WebViewController
detailVC.courseToPlay = self.courseToPlay
}
}
And, on WebViewController, i've a button to goBack on the list, whose i want to destroy instance of webViewController on goBack
I've not NavigationController in my storyBoard, so, this line doesn't work
navigationController.popViewControllerAnimated(true)
I use segue again to goBack :
performSegueWithIdentifier("closePlayer", sender: nil)
But each segue action instance a new view controller and they're never really free from memory, they seems to just be hiddens
eg : in Safari debugger i can see a lot of page and i can always interact with these in console
How to properly 'destroy' a view when scene change

Swift3:
self.dismiss(animated: true, completion: nil)
Hope it can help you.
Thanks

If it is a modal segue you can use
dismissViewControllerAnimated(true, completion: nil)
To dismiss the webViewController instead of another segue

Related

Make a segue to a tableview controller from a view controller

I am trying to make a segue to a table view controller when a button is tapped in my view controller programmatically. Here is my code:
#objc func editProfileButtonAction(sender: UIButton!) {
print("ButtonTapped")
func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let identifier = segue.identifier {
if identifier == "EditProfile" {
var editProfileTableViewController = segue.destination as! EditProfileTableViewController
editProfileTableViewController = self
}
}
}
}
I really could use some help. I also need to make a segue to a collection view controller using a button in the same view controller.
Okay to clarify that. There is no way to create a segue programmatically. Segues are the arrows on storyboard linking from one to another VC. They are called with: performSegue. This calls the function prepare.
If you want to show a new VC when hitting a button (without segue), then you use the present(VC(), animated: true, completion: nil) } inside the button function. The VC is presented modally.
#objc func editProfileButtonAction(sender: UIButton!) {
print("editProfileButtonAction")
present(EditProfileTableViewController(), animated: true, completion: nil)
}
Make sure, that the segue in the Storyboard has exactly the identifier: "EditProfile". Normally I'm writing identifiers with lower letter in the beginning. You also need to prepare for Segue. For example set the delegate:
// Set ViewController class as the delegate of the EditProfileTableViewControllerDelegate protocol
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let identifier = segue.identifier {
if identifier == "EditProfile" {
let editProfileTableViewController = segue.destination as! EditProfileTableViewController
editProfileTableViewController = self
}
}
}
At one point in my coding time, I deleted all my storyboard because of too many error's that I could hardly solve. Now I'm doing it all programmatically. At first it was a bit hard to set up all the view's by myself but after all I'm very glad I'm not using storyboards anymore. For some stuff I need xib's, and for testing storyboard. Just if you're interested: the most iOS programmers are using storyboard, so it's okay if you go on with that.
The advantage of doing it all programmatically is that there are no segue's anymore. So just present, and on navigation VC's push, pop, ...

how can i fix the error "Thread 1: signal SIGABRT"?

I have created a ViewController with a view and a button. I have declared the button as an outlet and as an Action in the viewcontroller. Additionally I am passing the data of the first Viewcontroller to the second Viewcontroller with a segue. When I click the cancel button which executes a segue back to the first viewcontroller I get the error
Thread 1: signal SIGABRT.
The error is shown in the prepare function which is passing the data. I have already controlled the connection inspector. I don't know what is wrong with my code.
here is my code:
#IBAction func cancelButton(_ sender: Any) {
performSegue(withIdentifier: "backToFirstScreen", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let tableViewVC = segue.destination as! tableViewController
tableViewVC.passwordNotes3 = passwordNotes2
tableViewVC.passwordCategory3 = passwordCategory2
tableViewVC.passwordStrings3 = passwordStrings2
}
I think the problem here is that you havent created a "backToFirstScreen" segue that starts in the second view controller and ends in the first viewcontroller.
Using a segue to go back to the first screen is slightly taboo; I would replace
performSegue(withIdentifier: "backToFirstScreen", sender: self)
with
self.dismiss(animated: true, completion: nil)
or if you're using a navigation controller
self.navigationController?.popViewController(animated: true)
This allows you to dismiss the current viewcontroller youre looking at and return to the view controller which presented it without having to create a segue that goes in reverse. Just make sure you have a segue that goes from the first view controller to the second view controller in that order.

Swift: How to dismiss a ViewController programmatically?

I got a little problem.
On my main view controller I got a bar button that opens a slide menu, which is a regular view controller using a slide in transition. The slide menu has a button to open another view controller. When the new view controller is opened, you have the option to cancel, which dismisses the current view controller. The problem is, that the user ends up in the menu view once again, instead of the main view controller. Would be very happy to know what I am doing wrong :)
func openSupport() {
guard let creditViewContoller = storyboard?.instantiateViewController(withIdentifier: "support") as? CreditViewController else { return }
present(creditViewContoller, animated: true)
}
#IBAction func buttonSupport(_ sender: UIButton) {
let menuView = MenuViewController()
menuView.dismiss(animated: true, completion: nil)
openSupport()
print("Tap on Support")
}
you can dismiss view controller simply by using
self.dismiss(animated: true, completion: nil)
Consider
#IBAction func buttonSupport(_ sender: UIButton) {
let menuView = MenuViewController() // (1)
menuView.dismiss(animated: true, completion: nil) // (2)
openSupport() // (3)
print("Tap on Support")
}
This:
Creates new MenuViewController but never presents it;
Calls dismiss on view controller that was never presented; and
Calls openSupport from this MenuViewController instance (which was never dismissed).
Bottom line, you want to let the main view controller that presented the menu do the presenting. So, the menu view controller should:
Define a protocol for it to inform the presenting view controller to transition to the next scene:
protocol MenuViewControllerDelegate: class {
func menu(_ menu: MenuViewController, present viewController: UIViewController)
}
And then the menu view controller can, when it’s done dismissing, tell its delegate what it should present:
class MenuViewController: UIViewController {
weak var delegate: MenuViewControllerDelegate?
#IBAction func didTapSupport(_ sender: Any) {
dismiss(animated: true) {
guard let controller = self.storyboard?.instantiateViewController(withIdentifier: "support") else { return }
self.delegate?.menu(self, present: controller)
}
}
#IBAction func didTapCancel(_ sender: Any) {
dismiss(animated: true)
}
}
Then the main view controller needs to
Make sure to set the delegate of the menu view controller:
class ViewController: UIViewController {
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destination = segue.destination as? MenuViewController {
destination.delegate = self
}
}
}
and
Make sure to present the view controller that the menu controller asked it to:
extension ViewController: MenuViewControllerDelegate {
func menu(_ menu: MenuViewController, present viewController: UIViewController) {
present(viewController, animated: true)
}
}
There are lots of different ways of achieving this, so don’t get lost in the details here. But the idea is to have some system by which the menu view controller can request whomever is to present the support view to do so, not try to do it itself.

How to close a popover from one viewcontroller by an action in another view controller

I have a popover (in AppDelegate.swift) that present from the status bar when the status bar icon is clicked. A button in this popover (in PopOverViewController) opens another view controller (NSViewController). I want the popover to close when this button is clicked. How do you make this happen?
class PopOverViewController: NSViewController {
#IBAction func showViewController(sender: Any) {
AppDelegate().popOver.performClose(sender)
performSegue(withIdentifier: NSStoryboardSegue.Identifier(rawValue: "seque"), sender: self)
}
}
Put this on the first line of the action that the button triggers.
self.dismiss(animated: true, completion: nil)
if you present using modal,try this one
self.dismiss(animated: true, completion: nil)
or if you present the view using "push" segue
self.navigationController?.popViewController(animated: true)

nothing happens on trying to dismiss popover viewcontroller Swift

I have a viewcontroller that is presented as popover when the user clicks on an ImageView.
The problem is, I added a button to dismiss it but when I tap on it nothing happens.
The code I have is:
#IBAction func onCloseTapped(_ sender: Any) {
presentedViewController?.dismiss(animated: true, completion: nil)
}
I've also tried dismiss(animated: true, completion: nil) and other methods, but still nothing.
Can anyone tell me what I am doing wrong?
Edit: Posting a screenshot:
Edit 2: I'm presenting it from the storyboard. I've added a gesture recognizer on the image, then added segue from the storyboard that says present as popover, then anchor to the image.
it won't work because when you show as popover, the viewController doesn't have the navigationController. You have to create a delegate method and use the dismiss function on the viewController that make the call to the popover.
Here an exemple:
make the popover delegate, in the popover viewController:
protocol PopoverViewControllerDelegate: NSObjectProtocol {
func dismiss()
}
then you create a delegate variable and call when the button is tapped:
var delegate: PopoverViewControllerDelegate?
#IBAction func onCloseTapped(_ sender: Any) {
delegate?.dismiss()
}
Now in the viewController that call the popover you override the prepare for segue method to set the popover delegate:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "popover" {
if let vc = segue.destination as? PopoverViewController {
vc.delegate = self
}
}
}
Now you just need to use the delegate to dismiss your popover viewController:
extension ViewController: PopoverViewControllerDelegate {
func dismiss() {
navigationController?.dismiss(animated: true, completion: nil)
}
}
Don't forget to put the identifier for you segue, the identifier that we use is this = "popover"
Hope that help you.