仅当视图控制器通过滑动或后退按钮按下而不是通过切换选项卡从堆栈中弹出时才发送数据

Send data only if view controller is being popped off stack by swipe or back button press but not by switching tabs

我查看了 SO 并在下面编译了这些方法,但其中 none 对我有用。

我有一个带有 2 个选项卡的 TabBarController。在第二个选项卡中,我有一个 NavigationController > TableViewController > DetailViewController。

在我的 DetailViewController 中,我有一个自定义委托,用于在按下后退按钮或将视图滑动至关闭(向右滑动)时将一些数据发送到 TableViewController。我只希望在“后退按钮”或“滑动以关闭”完全完成时发送数据,而在切换选项卡或滑动 3/4 的方式时不发送数据,但用户决定不完成后退滑动(基本上它们保持打开状态相同的 DetailVC 场景)。

我尝试了下面的所有这些方法,它们要么在选项卡切换到第一个选项卡时触发,要么在 DetailVC 被推开和弹出时触发,要么在以 1/2 方式滑动以关闭 DetailVC 时触发仍然 运行 意味着数据不应该被发送。

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)
    }
}

表视图控制器:

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
}

}

TableView 在接收数据时从来没有问题。问题是当我切换选项卡(数据仍被发送)或在 DetailVC 上滑动以关闭时未完全完成(数据仍被发送)。

从 DetailVC 发送数据的最佳方法是什么,但要确保按下后退按钮或向右滑动以关闭已完全完成?

您需要使用自定义后退按钮和委托来调用 parent。 这是你的 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()
    }

}

这是 child 视图控制器,您想从它返回到您的 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)
    }

}

以上代码,处理后退按钮和后退手势。