Let's say I have my initial vc called VC1, then I have a second one called VC2. VC1 has a segue to VC2, on VC2 there is a button that will dismiss VC2 and then show VC1. Once VC1 loads I want to run a method but I can't do that in view did load so where can I do it?
[VC1] -> [VC2]
You can also try Unwind Segue for dismissing the VC2 and call methods in VC1. It is very easy and requires less coding.
In your VC1 add below method:
#IBAction func unwindToVC1(segue:UIStoryboardSegue){
print("Hello")
}
In storyboard right click on Exit icon of VC1 and and connect a segue to VC2:
Then in storyboard in VC2 select the unwindSegue and name it :
now in the method where you are dismissing the VC2 just add:
performSegue(withIdentifier: "dismissSegue", sender: self)
you can also pass data from VC2 to VC1.
You can use a delegate method to achieve this. In the method you call to dismiss VC2 call the delegate. You can implement this delegate in VC1.
In VC1:
Delegate of VC2 and in VC1 Controller in Class or extension
add the delegate method into VC1 that would called after dismiss the VC2
In VC2:
Add the protocol of VC1 and make the object of Protocol delegate then its segue exit it goto VC1 Delegate method.
Example:
VC1:
extension VC1, myCustomVC2Delegate {
func didCloseDelegate() {
// Your function or method Called here
}
}
VC2:
protocol myCustomVC2Delegate {
func didCloseDelegate()
}
import UIKit
class VC2: UIViewController {
var delegate: myCustomVC2Delegate?
#IBAction func onTapGotoVC1(_ sender: AnyObject) {
self.performSegue(withIdentifier: "gotoVC1", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "gotoVC1" {
if self.delegate != nil {
self.delegate?.didCloseDelegate()
}
}
}
Related
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.
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.
I'm trying to perform a segue from ViewController A to ViewController A (same VC). I can do that when I ctrl+drag from a button to the VC and set the identifier ("sameVC" in my case).
When the button is tapped, the segue works as expected. The problem is, I need to call
self.performSegue(withIdentifier: "sameVC", sender: self)
from a delegate. So when the button is tapped, I need to call a function, that has a delegate, like this:
class ViewControllerA: ViewController, MyDelegate {
var mC = MyClass()
override func viewDidLoad() {
mC.delegate = self
}
#IBAction func buttonTapped(_ sender: UIButton) {
mC.myfunc()
}
func success {
// Trying to call delegate
self.performSegue(withIdentifies: "sameVC", sender: self)
}
}
protocol MyDelegate {
func success()
}
class MyClass {
var delegate: MyDelegate?
func myfunc() {
// ...
self.delegate.success()
}
}
When the delegate comes back to ViewControllerA in "success"-function, I want to perform the segue, but the View isn't present anymore, because the segue was called implicit with "buttonTapped"-function.
When the segue isn't going to the same VC, I would just ctrl+drag from ViewControllerA to ViewControllerB, but this isn't possible with only one ViewController (or I don't know how to do this).
Is there any way I can achieve this?
Instead of ctrl+dragging from button, ctrl+drag from ViewController itself, then it will wait for you to call performSegue
And for going from you have more than one viewcontrollers you may want to navigate to, you can assign an Identifier to your viewControllers in your storyboard and use storyboard.instantiateViewControllerWithIdentifier method to instantiate your desired ViewController and present it to the user, e.g. push it on top of current viewcontroller.
I have two view controllers, HomeViewController, and SecondViewController, which is pushed on top of HomeViewController at the top of the stack. I have a segue from HomeVC to SecondVC by means of 'Show'. I understand how to pass information from SecondVC to HomeVC - using the prepare for segue method using identifiers. But I do not have a segue from SecondVC to HomeVC, as it is embedded in a navigation controller. How would I pass information, for example a string, from SecondVC back to HomeVC upon popping the SecondVC from the navigation stack?
You need to pass a ViewModel from the HomeViewController to the SecondViewController, what you do is give your Segue an Identifier and then override prepareForSegue in your HomeViewController:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
if segue.identifier == "mySegueIdentifier" {
if let destination = segue.destinationViewController as? SecondViewController {
destination.aViewModel = aViewModel;
}
}
}
In your SecondViewController you need to declare the ViewModel:
class SecondViewController: UIViewController {
var aViewModel: AViewModel?
//rest of code
}
And create a ViewModel, use a struct type:
struct AViewModel
{
let AValueIWantToPassAround: String
let AnotherValueIWantToPassAround: Int
}
SWIFT: In my storyboard, embedded in a NavigationController, I have a ViewcontrollerA which needs to either present itself repeatedly OR present ViewcontrollerB based on an if clause.
I've implemented the logic in the prepareForSegue method. I've drawn a segue from ViewcontrollerA to ViewControllerB.
if (someClause == true)
{
let svc = segue.destinationViewController as! ViewControllerA
} else {
let svc = segue.destinationViewController as! ViewControllerB
}
Executing this code results the following error:
Could not cast value of type 'ViewControllerB' to 'ViewControllerA' .
That's because there is no segue from ViewControllerA to ViewControllerA. The segue is from ViewControllerA to ViewControllerB.
Is there a way for one "Button" to have multiple segues? One to ViewControllerA (itself) and one to ViewControllerB. I know this is possible for TableViewCells.
Side note, I have managed to get instantiateViewControllerWithIdentifier followed by a call to presentViewController to do what I want, but that destroys my NavigationStack and TabBar. I DONT want to go this route because it seems like a lot of patch work.
You should create a segue between from ViewControllerA to ViewControllerB, not the button to ViewControllerB. Then do something like:
#IBAction func buttonPressed(sender: UIButton) {
if (someClause == true)
{
// Stay on ViewControllerA
} else {
performSegueWithIdentifier("showB", sender: AnyObject)
}
}
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
if (segue.identifier == "showB") {
let _ = segue.destinationViewController as? ViewControllerB
}
}