1

I looked through SO and compiled these methods below but none of them works for me.

I have a TabBarController with 2 tabs. In the Second tab I have a NavigationController > TableViewController > DetailViewController.

In my DetailViewController I have a custom delegate to send some data to the TableViewController when the Back Button is pressed or the view is Swiped to Dismiss (right swipe). I only want the data sent when the Back Button or Swipe to Dismiss is fully finished and not get sent when the tab is switched or if swiping 3/4 of the way but the user decides NOT to complete the back swipe (basically they stay on the same DetailVC scene).

I tried all of these methods below and they either get triggered when the tab is switched to the first tab, when the DetailVC gets pushed on and popped off, or during the 1/2 way Swipe to Dismiss the DetailVC they still run meaning the data should not have been sent.

DetailViewController:

protocol DetailViewDelegate: class {
    func sendSomeData(value: Bool)
}

class DetailViewController: UIViewController{

weak var delegate: DetailViewDelegate?

//1. runs when Tab switches, the Back Button is pressed, and Swipe to Dismiss is triggered
override func viewWillDisappear(_ animated : Bool) {
        super.viewWillDisappear(animated)
        if (self.isMovingFromParentViewController) || (self.isBeingDismissed){
            //doesn't run at all
        }else{
            //runs whenever view is no longer on scene
            sendData()
        }
    }

//2. runs when Tab switches, Back Button is pressed, Swipe to Dismiss is triggered, and when the view is Pushed on AND Popped off
override func didMove(toParentViewController parent: UIViewController?) {
        if parent != nil {
            sendData()
        }else{
            //if parent == nil doesn't run at all
        }
    }

//3. if switching from the second tab it doesn't run but when switching back to the second tab it does run, also runs when view is being Pushed on and Not Popped on
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
         sendData()
    }

//4. if switching from the second tab it doesn't run but when switching back to the second tab it does run, also runs when view is being Pushed on and Not Popped on
func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {
         sendData()
    }

//MARK:- Custom Func
    fileprivate func sendData(){
        let value = true
        delegate?.sendSomeData(value: value)
    }
}

TableViewController:

class TableVC: UIViewController, DetailViewDelegate, UITableViewData..., UITableViewDele...{

var setValue = false

func sendSomeData(value: Bool){

     //setValue should only update to true if DetailVC's Back Button is pressed or Right Swipe to Dismiss is fully complete
     self.setValue = value
}

}

The TableView never has a problem receiving the data. The problem is when I switch tabs (data still gets sent) or a swipe to dismiss on the DetailVC isn't fully completed (data still gets sent).

What's the best way to send the data from the DetailVC but making sure the Back Button is pressed or Right Swipe to Dismiss is fully complete?

Eric Aya
  • 69,473
  • 35
  • 181
  • 253
Lance Samaria
  • 17,576
  • 18
  • 108
  • 256
  • Can you add your table view delegate methods ? – Muhammed Jun 12 '17 at 11:25
  • @Muhammed this has nothing to do with the tableView methods, that works fine and the data gets sent successfully using a delegate method. The issue is I want to send it back only if the back button is pressed or a right swipe has been fully completed. Switching tabs or a 1/2 right swipe should not send the data. Even if i wasn't;t using a tableView the problem would still occur. – Lance Samaria Jun 12 '17 at 11:27
  • are you sure that TableVC is calling func sendSomeData or not ? – Muhammed Jun 12 '17 at 11:30
  • @Muhammed that is a delegate method. The data always gets sent. That's not the problem, The problem is the data gets sent when i switch tabs or a swipe to dismiss is 1/2 completed. This isn't an issue with receiving the data. – Lance Samaria Jun 12 '17 at 11:33
  • sorry for misunderstand – Muhammed Jun 12 '17 at 11:35
  • 1
    @Muhammed np man, I appreciate the help! :) – Lance Samaria Jun 12 '17 at 11:36

1 Answers1

0

You need to use custom back button and a delegate to call the parent. this is your parent ViewController:

import UIKit

class ViewController: UIViewController, ViewControllerSecondDelegate {

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "Next" {
            let vc = segue.destination as? ViewControllerSecond
            vc?.delegate = self
        }
    }

    func secondDelegate() {
        print("delegate") //GetData()
    }

}

and this is the child view controller, which you want to back from it to your parent:

import UIKit

protocol ViewControllerSecondDelegate {
    func secondDelegate()
}

class ViewControllerSecond: UIViewController, UIGestureRecognizerDelegate {

    var isTouched = false
    var isPopTouch = true
    var delegate: ViewControllerSecondDelegate?

    override func viewDidLoad() {
        super.viewDidLoad()
        self.navigationController?.setNavigationBarHidden(false, animated:false)
        let myBackButton:UIButton = UIButton.init(type: .custom)
        myBackButton.addTarget(self, action: #selector(ViewControllerSecond.popToRoot(sender:)), for: .touchUpInside)
        myBackButton.setTitle("Back", for: .normal)
        myBackButton.setTitleColor(.blue, for: .normal)
        myBackButton.sizeToFit()
        let myCustomBackButtonItem:UIBarButtonItem = UIBarButtonItem(customView: myBackButton)
        self.navigationItem.leftBarButtonItem  = myCustomBackButtonItem
        self.navigationController?.interactivePopGestureRecognizer?.delegate = self
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        if isTouched {
            isPopTouch = true
        }
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        self.isPopTouch = false
    }

    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        if isPopTouch {
            delegate?.secondDelegate()
        }
    }

    func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        if gestureRecognizer == self.navigationController?.interactivePopGestureRecognizer {
            self.isTouched = true
        }
        return true
    }

    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        self.isTouched = false
    }

    func popToRoot(sender:UIBarButtonItem){
        delegate?.secondDelegate()
        self.navigationController?.popToRootViewController(animated: true)
    }

}

the above code, handle back button and back gesture.

Mina
  • 2,167
  • 2
  • 25
  • 32
  • thanks I tried that already, it didn't work. In the DetailViewController look at #2 and #3. It fired even when switching tabs. – Lance Samaria Jun 12 '17 at 11:47
  • well, which one is the problem,? in #3 you said it didn't call at all. and in #2 you said something else – Mina Jun 12 '17 at 11:50
  • I put them both there to show that neither worked. #3 didn't call at all so the problem with that is it doesn't work. #2 gets called when switching tabs and pushing on which is also a problem. – Lance Samaria Jun 12 '17 at 11:53
  • aren't thay the same? what i see is #2 and #3 are the same thing? – Mina Jun 12 '17 at 12:12
  • it called when switching the tabs, but you can handle it with checking parent type with casting to correct parent controller – Mina Jun 12 '17 at 12:13
  • look closely #2 is "if parent != nil" and #3 is "if parent == nil". I could've just used #2 with an else statement and achieved the same thing as both of them combined – Lance Samaria Jun 12 '17 at 12:15
  • I tried casting but that didn't work either. I tried "if let parent = parent as? TableVC{ } it didn't run. I printed (navigationController?.viewControllers) and DetailVC was the only one on the stack. – Lance Samaria Jun 12 '17 at 12:19
  • I just tried again using "if let parent = parent as? UINaviagtionController{ print("something") } and at least it prints but it prints while pushing, popping, and switching tabs which i don't want – Lance Samaria Jun 12 '17 at 12:33
  • after casting to UINavigationController, you have to cast the topViewController of the navigationController to your desire controller. – Mina Jun 12 '17 at 12:35
  • I tried your new way but it didn't work. I then printed (parent.topViewController) and it's saying the DetailVC is the topviewcontroller. I instead cast it as parent.topViewController as? DetailViewController but the same problem occurs, i get print statements even when i switch tabs or the vc gets pushed on. Btw thanks for the help! – Lance Samaria Jun 12 '17 at 12:56
  • hey thanks, i'm going to try your updated answer in about 1 hour or less. What do you think about adding a completion handler to popViewController -https://stackoverflow.com/questions/12904410/completion-block-for-popviewcontroller/27229945#27229945 -specifically Arbitur's answer (Benobab's is updated for Swift 3).The completion handler to pop is custom, I tried it earlier this morning I just didn't know where to call it – Lance Samaria Jun 12 '17 at 17:28
  • I copied your code exactly (of course I changed the vc names). I get see the new back button and when I press it the print("delegate") runs but I can't right swipe to dismiss nor does the back button pop the vc. Later tonight I will try and debug it but right now it's not working. Thanks though :) – Lance Samaria Jun 12 '17 at 19:10
  • i checked it again, it works correctly, let me know if there is still a problem. – Mina Jun 13 '17 at 04:10
  • I still haven't gotten a chance to get to it. Very strange it works for you and I c+p the code and made the appropriate changes. I must've did something wrong/\. I give you a shout tomorrow evening. Thanks – Lance Samaria Jun 13 '17 at 07:02