0

Solved it: I forgot to declare tvx.selectionDelegate = self in VC1, thats why it never executed

I'v searched very long and fund two similar answers to my problem online: here

But all of them work with dismissing and then presenting another view, and I want to dismiss and PUSH another ViewC.

I have 3 ViewController:

VC1 lets Call it: DownloadsViewController

VC2 lets Call it: SelectActionController

VC3 lets Call it: fileInfoView

VC1 presents VC2 modally then VC2 should dismiss and VC1 should PUSH VC3 immediately.


I've tried:

VC2:

self.present(vx, animated: true, completion: nil) 

and the to put the PUSH animation in completion {} but it crashes.


The next thing I've tried is to make a delegate and if I press a button on VC2 it call VC1 to dismiss VC2 and Push VC3. Like Here:

VC2:

protocol PushViewControllerDelegate: class {
func pushViewController(_ controller: UIViewController)
}

class SelectActionController: UIViewController, UITableViewDelegate, UITableViewDataSource {
weak var delegate: PushViewControllerDelegate?

public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{

    if self.delegate != nil {
        self.delegate?.pushViewController(self)}

VC1:

func pushViewController(_ controller: UIViewController) {

        controller.dismiss(animated: true) { () -> Void in

            self.performSegue(withIdentifier: self.segue2, sender: nil)

            //let vx = self.storyboard?.instantiateViewController(withIdentifier: "FileInfo") as! fileInfoView
            //self.navigationController?.pushViewController(vx, animated: false)

        }
    }

The Trird thing I tried was to make a global Variable and if it dismisses, just set a Bool variable to true and an func in VC1 should recognize it(my intention). Only problem it doesn't regognize dismissing as ViewDidAppear or stuff like that.


So none of that worked.

Does anyone has an Idea to this?

  • Can you post some code? – Everton Cunha Sep 29 '17 at 14:19
  • *and the to put the PUSH animation in completion {} but it crashes.* - what's the error message? Do you add that animation in completion block on main thread? – mag_zbc Sep 29 '17 at 14:19
  • @EvertonCunha Which Controller or Code, I could even share the whole Code if it would help? –  Sep 29 '17 at 14:21
  • Post your completion block code. – Pranav Kasetti Sep 29 '17 at 14:23
  • @PranavKasetti I did –  Sep 29 '17 at 14:28
  • See [modal View controllers - how to display and dismiss](https://stackoverflow.com/questions/14907518/modal-view-controllers-how-to-display-and-dismiss). The accepted answer goes into great details of different ways and their pros and cons. Though it's in Objective-C. However there is another answer, written in Swift. See [this](https://stackoverflow.com/a/27435406/5175709) answer. – Honey Sep 29 '17 at 15:10
  • @Honey how does that help? I know how to dismiss, the problem in after dismissing –  Sep 29 '17 at 15:37
  • Did you read the answers? Or you're just asking without reading it? – Honey Sep 29 '17 at 15:42
  • @Honey like in my decription I also found solution with dismissing and PRESENTING new VC but not with dismissing and Pushing. SOmehow there is a diffrence –  Sep 29 '17 at 15:44
  • 1. In your own code, are you *setting* the `delegate` property anywhere? Because without that the two classes would never be able to communicate! 2. The act of dismissing a viewController should be sent to the *presenting* viewcontroller. In your code you're doing: `controller.dismiss(animated: true)`, which means the *presented* controller itself, is attempting to dismiss itself. (It may work or may not. But just **don't** do it). Simply put, just do `dismiss(viewcontroller)` – Honey Sep 29 '17 at 16:00
  • 3. After you fixed all these issues, use a breakpoint and make sure you're actually reaching the performSegue line 4. It may be that your controller's identifier name isn't correct in the Storyboard, so just to be sure this isn't an issue related to Pushing, just try Presenting the viewController for once and see if it works. If it does work then you know for sure your problem is related to pushing. If that doesn't work too, then you know your problem isn't specific to pushing! – Honey Sep 29 '17 at 16:03

5 Answers5

2

EDITED after OP comment

Just use a protocol. Let your first controller adopt it, and add the required function. Set a protocol variable in the second controller who takes the first one for reference and call the function when you dismiss the second controller. You can now use the dismiss function to do whatever you want, pass data, send to an other controller...

first view controller :

protocol CustomProtocol {
    func dismissed()
}

class AViewController: UIViewController, CustomProtocol {

    @IBOutlet weak var button: UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    @IBAction func toVC2(_ sender: UIButton) {
        let VC = self.storyboard!.instantiateViewController(withIdentifier: "BViewController") as! BViewController
        VC.customProtocol = self
        VC.view.backgroundColor = .white
        self.present(VC, animated: true, completion: nil)
    }

    func dismissed() {
        let yourViewController = UIViewController()
        yourViewController.view.backgroundColor = .red
        guard let navigationController = self.navigationController else {return}
        navigationController.pushViewController(yourViewController, animated: true)
    }
}

second view controller :

class BViewController: UIViewController {

    var customProtocol: CustomProtocol?

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    @IBAction func quit(_ sender: UIButton) {
        self.dismiss(animated: true) {
            guard let proto = self.customProtocol else {return}
            proto.dismissed()
        }
    }
}
Honey
  • 24,125
  • 14
  • 123
  • 212
Damien Bannerot
  • 2,965
  • 2
  • 17
  • 27
  • The Problem is not the Code to Push from VC1 to VC3. I know alot of ways to do that. The problem is to execute Code from VC1 when VC2 is dismissed –  Sep 29 '17 at 14:33
  • Ok I didn't understand that, I edited my answer, it's a basic use of a protocol I declared. Hope that helps with your problem – Damien Bannerot Sep 29 '17 at 14:59
  • Are you sure you don't need to put the "guard let proto..." in completion: at the 2nd VC? –  Sep 29 '17 at 15:32
  • I did use a guard statement in the 2nd controller – Damien Bannerot Sep 29 '17 at 16:02
0

I hope you need to perform the dismiss action on your

public func tableView(_ tableView: UITableView, didSelectRowAt indexPath:

in "SelectActionController" right ?

In such case you have to do as follows,

public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

if self.delegate != nil {
     dismiss(animated: true) {
        self.delegate?.pushViewController(self)}
    }
}

I have shared an example project related to your situation, please refer it. https://github.com/Bharath-MallowTech/StackoverflowSolutions/tree/master/viewcontrollerDismissAndPush

Bharath
  • 1,924
  • 1
  • 11
  • 37
  • Yes the didSelectRow at is in VC2 aka SelectActionController –  Sep 29 '17 at 14:43
  • @ChrisBerger: Then do the delegate call in dismiss block completion as in the code shared. It worked fine for me. If you need reference then checkout the project in the link. – Bharath Sep 29 '17 at 14:44
  • I can't even build the App bc It doesn't recognize self in pushViewController(self) –  Sep 29 '17 at 14:51
  • @ChrisBerger: It seems you got multiple answers for this question, so a small note here for you, my suggestion is don't use Notification approaches recommended since I have faced many issue in it due to time issue on notifications. – Bharath Sep 29 '17 at 14:51
  • @ChrisBerger: Is it mandatory for you to pass the viewcontroller, is there any use of passing the view controller ? – Bharath Sep 29 '17 at 14:54
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/155608/discussion-between-bharath-and-chris-berger). – Bharath Sep 29 '17 at 14:56
  • No it isn't, I already corrected it. I don't need to pass any Data –  Sep 29 '17 at 14:56
0

Could you post some code on what you've been trying? What is self here? Is it VC1, VC2 or VC3?

What you could do is have a look at protocols, so you use VC1 as a delegate and when you dismiss VC2 it will also call it's delegate showVC3(). You then place that delegate.showVC3() in the completion block for your dismiss.

// Declare it in VC1
@protocol MyDelegate {
    func showVC3()
}

class VC1: UIViewController, MyDelegate {
    var vc2: VC2ViewController = VC2ViewController()
    var vc3: VC3ViewController = VC3ViewController()

    func showVC2() {
        vc2.delegate = self
        self.present(self.vc2)
    }

    func showVC3() {
        self.present(self.vc3)
    }
}

// In VC2
class VC2: UIViewController {
    var delegate: MyDelegate?

    func closeVC2() {
        self.dismiss(animated: true, completion: {
            self.delegate?.showVC3()
        })
    }
}

Not sure if this works, haven't tried it out since I'm on my PC at the moment. But change it according to your needs and test it out.

ClockWise
  • 1,449
  • 11
  • 29
  • Doesn't work, I don't know why, I also tried just to print smth. out but func showVC3() never gets executed. Mybe that only works with present. Again I want it to PUSH –  Sep 29 '17 at 14:48
0

According to your File from Github, I think you forgot to declare

tvx.selectionDelegate = self

in the

func imagePressed
John Smith
  • 485
  • 3
  • 20
0

Even i had the same situation , that after presenting a view controller , i need to push to some other view controller. If we have vc1, vc2, vc3, We presented vc2 from vc1, then on button click of vc2 we need to push to vc3, what i did is, i set vc3 as root view controller. You can check code as per below.

func goToHomeScreenPage(transition : Bool)
{
    let _navigation : UINavigationController!

    let startVC : TabbarViewController = Utilities.viewController(name: "TabbarViewController", onStoryboard: StoryboardName.Login.rawValue) as! TabbarViewController

    _navigation = UINavigationController(rootViewController: startVC)

    _navigation.setNavigationBarHidden(true, animated: true)

    let transitionOption = transition ? UIViewAnimationOptions.transitionFlipFromLeft : UIViewAnimationOptions.transitionFlipFromLeft
    gotoViewController(viewController: _navigation, transition: transitionOption)

}

the above method gotoviewcontroller() is below,

func gotoViewController(viewController: UIViewController, transition: UIViewAnimationOptions)
{
    if transition != UIViewAnimationOptions.transitionCurlUp
    {
        UIView.transition(with: self.window!, duration: 0.5, options: transition, animations: { () -> Void in
            self.window!.rootViewController = viewController
        }, completion: { (finished: Bool) -> Void in
            // do nothing
        })
    } else {
        window!.rootViewController = viewController
    }
}

Declare var window: UIWindow? on top, you can write these methods in appdelegate and call them by creating appdelegate instance.

Arshad Shaik
  • 782
  • 8
  • 16