我有一个带有三个viewControllers的相当简单的应用程序。您可以在下面看到它们:

ios - 一个ViewController调用另一个ViewController的委托(delegate)方法-LMLPHP

我希望两个控制器在设定的时间后都回到初始屏幕,但前提是用户不与该应用进行交互。为此,我使它们都符合UITextFieldDelegate协议,因此我可以使用一些不同的委托函数来了解用户与文本字段进行交互的时间。这两个viewController都包含以下UITextFieldDelegate函数,并且都具有变量segueTimer,每次用户与文本字段进行交互时,我都会重置该变量:

我将尝试仅发布与该问题相关的代码。

CheckInViewController

class CheckInViewController: UIViewController, UITextFieldDelegate {

    @IBOutlet weak var checkInView: CheckInView!

    var segueTimer: Timer?

    var fireTime = TimeInterval(20)

    var delegate: CheckInViewControllerDelegate!

    override func viewDidLoad(){

        super.viewDidLoad()

        checkInView.searchTextField.delegate = self

    }

    override func viewDidAppear(_ animated: Bool) {

        resetSegueTimer()
    }

    override func viewWillDisappear(_ animated: Bool) {

        deregisterFromKeyboardNotifications()
        //segueTimer?.invalidate()
        stopTimer()
    }


    func keyboardWillShow(sender: Notification){
        //print("keyboardWillShow()")

        ...

        resetSegueTime()
    }


    //This function fires everytime text changes
    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {

        resetSegueTimer()

        return true
    }

    func textFieldDidBeginEditing(_ textField: UITextField) {

        resetSegueTimer()

    }

    func textFieldDidEndEditing(_ textField: UITextField) {


    }

    func resetSegueTimer(){

        stopTimer()
        startTimer()

    }

    func startTimer(){
        print("@CheckInVC  startTimer() \(segueTimer)")
        if segueTimer == nil{
            segueTimer = Timer.scheduledTimer(timeInterval: fireTime, target: self, selector: #selector(unwindToSplash), userInfo: nil, repeats: false)
         }
    }

    func stopTimer(){
        print("@CheckInVC  stopTimer() \(segueTimer)")
        if segueTimer != nil {
            segueTimer!.invalidate()
            segueTimer = nil
        }
    }

    func unwindToSplash(){
        self.performSegue(withIdentifier: "UnwindViewControllers", sender: self)
    }

}


CheckInViewControllerDelegate

protocol CheckInViewControllerDelegate {
    var todaysGuests: NSMutableArray? { get set }
    var currentGuest: NSMutableDictionary? { get set }
    var guestRegisteredInKlik: Bool! { get set }
}


RegisterViewController

class RegisterViewController: UIViewController, CheckInViewControllerDelegate, UITextFieldDelegate {

    var segueTimer: Timer?
    var fireTime = TimeInterval(20)

    var currentGuest: NSMutableDictionary?
    var todaysGuests: NSMutableArray?
    var guestRegisteredInKlik: Bool!

    @IBOutlet weak var registerView: RegisterVisitorView!

    override func viewDidLoad() {
        super.viewDidLoad()

        self.registerView.companyTextField.delegate = self
        self.registerView.hostTextField.delegate = self
    {

    override func viewWillDisappear(_ animated: Bool) {

        registerView.nameLabel.text = ""
        registerView.companyTextField.text = ""
        registerView.hostTextField.text = ""

        stopTimer()
    }

    override func viewDidAppear(_ animated: Bool) {

        resetSegueTimer()

    }


    //delegate method to differntiate between multiple textfields that have the VC as their delegate
    func textField(_ textFieldToChange: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {

        if textFieldToChange == self.registerView.companyTextField {
            resetSegueTimer()

            return true

        } else if textFieldToChange == self.registerView.hostTextField {
            resetSegueTimer()

            return true
        }

        return true
    }

    func textFieldDidBeginEditing(_ textField: UITextField) {

        resetSegueTimer()

    }

    func textFieldDidEndEditing(_ textField: UITextField) {

    }

    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        textField.resignFirstResponder()

        return true
    }

    func resetSegueTimer(){

        stopTimer()
        startTimer()

    }

    func startTimer(){
        print("@RegisterVC  startTimer() \(segueTimer)")
        if segueTimer == nil{
            segueTimer = Timer.scheduledTimer(timeInterval: fireTime, target: self, selector: #selector(unwindViewControllers), userInfo: nil, repeats: false)
        }
    }

    func stopTimer(){
        print("@RegisterVC  stopTimer() \(segueTimer)")
        if segueTimer != nil {
            segueTimer!.invalidate()
            segueTimer = nil
        }
    }

}


我遇到的问题涉及最后两个viewControllers,一个是自定义类型CheckInViewController,另一个是RegisterViewController。我在两个委托方法(textFielDidBeginEditing)中有打印语句,每个viewController中都有一个。当我进入RegisterViewController并切换到其他文本字段时,我看到调用了第一个viewController的textFieldDidBeginEditing函数的print语句,而不是我所在的viewController的函数。

打印语句仅显示错误行为。实际的问题是,当我在第二个viewController中更改textFields时,将调用firstViewController的resetSegueTimer()函数。同样,在第二个viewController中调用的textField(shouldChangeCharactersIn range:)函数永远不会使它的viewController中的segueTimer无效,因此当用户编辑文本字段时,不会重置返回初始的segueTimer。

我想象这是我使两个viewController遵循相同的委托协议,同时又使第二个viewController成为第一个viewController的委托的问题。但是,我不确定如何解决此问题。

**编辑:在CheckInViewController描述中添加了keyBoardWillShow()函数,因为它导致了问题……该函数被RegisterViewController调用。仍然不确定如何。

最佳答案

通过从第一个viewController中的keyboardWillShow()移除resetSegueTimer()来解决此问题。这使resetSegueTimer被调用了两次,一次是在keyboardWillShow中,然后是在EditingDidBegin中,这是多余的。当键盘弹出时,第二个viewController也以某种方式调用了此函数...仍然不确定如何实现。

我认为这不是应用程序的最佳解决方案,OverD提供了更好的解决方案。最终将应用它。

关于ios - 一个ViewController调用另一个ViewController的委托(delegate)方法,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/47291872/

10-10 15:21