一个ViewController调用另一个ViewController的委托方法

时间:2021-04-07 20:45:36

I have a fairly simple app with three viewControllers. You can see them below:

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

一个ViewController调用另一个ViewController的委托方法

I want both controllers to segue back to the splash screen after a set amount of time, but only as long as a user isn't interacting with the app. To do this I have them both conform to UITextFieldDelegate protocol so I can use a few different delegate functions to understand when the user interacts with text fields. Both viewControllers incorporate the following UITextFieldDelegate Functions, and both have a variable segueTimer that I reset every time a user interacts with a text field:

我希望两个控制器在一段时间后切换回启动屏幕,但只要用户没有与应用程序交互。为此,我让它们都符合UITextFieldDelegate协议,因此我可以使用一些不同的委托函数来了解用户何时与文本字段交互。两个viewControllers都包含以下UITextFieldDelegate函数,并且都有一个变量segueTimer,我每次用户与文本字段交互时都会重置它:

I'll try to post only code that is relevant to the issue.

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

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

}

The problem I am having involves the last two viewControllers, one of custom type CheckInViewController, and the other RegisterViewController. I have print statements in two delegated methods, textFielDidBeginEditing, one in each viewController. When I am in RegisterViewController and I switch to a different textfield, I see that the print statement of the textFieldDidBeginEditing function of the first viewController is called instead of the function of the viewController I am in.

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

The print statement just shows me the incorrect behavior. The actual problem is that the resetSegueTimer() function of the firstViewController is being called when I change textFields in the second viewController. Also, the textField(shouldChangeCharactersIn range: ) function called in the second viewController never invalidates the segueTimer in it's viewController, so the segue back to the splash isn't reset when a user edits the textfield.

print语句只是向我显示了不正确的行为。实际问题是当我在第二个viewController中更改textFields时,正在调用firstViewController的resetSegueTimer()函数。此外,在第二个viewController中调用的textField(shouldChangeCharactersIn range :)函数永远不会使其viewController中的segueTimer无效,因此当用户编辑文本字段时,不会重置回到启动画面的segue。

I imagine this is an issue with me making two viewControllers conform to the same delegate protocol, while also making the second viewController the first viewController's delegate. But, I'm not sure how to fix this.

我想这是一个问题,我让两个viewControllers符合相同的委托协议,同时也使第二个viewController成为第一个viewController的委托。但是,我不知道如何解决这个问题。

**Edit: Added keyBoardWillShow() function to CheckInViewController description, as it was contributing to the problem... that function was being called by RegisterViewController. Still not sure how, though.

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

1 个解决方案

#1


0  

Fixed issue by removing resetSegueTimer() from keyboardWillShow() in first viewController. This had resetSegueTimer being called twice, once in keyboardWillShow and then again in EditingDidBegin, it was redundant. This function was also somehow being called by the second viewController when the keyboard would pop up... still not sure how that was possible.

通过在第一个viewController中从keyboardWillShow()中删除resetSegueTimer()来解决问题。这有两次调用resetSegueTimer,一次在keyboardWillShow中,然后再在EditingDidBegin中,它是多余的。当键盘弹出时,第二个viewController也会以某种方式调用此函数...仍然不确定这是怎么回事。

I don't think this is the best fix for the application, and OverD gave a better solution. Will apply it eventually.

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

#1


0  

Fixed issue by removing resetSegueTimer() from keyboardWillShow() in first viewController. This had resetSegueTimer being called twice, once in keyboardWillShow and then again in EditingDidBegin, it was redundant. This function was also somehow being called by the second viewController when the keyboard would pop up... still not sure how that was possible.

通过在第一个viewController中从keyboardWillShow()中删除resetSegueTimer()来解决问题。这有两次调用resetSegueTimer,一次在keyboardWillShow中,然后再在EditingDidBegin中,它是多余的。当键盘弹出时,第二个viewController也会以某种方式调用此函数...仍然不确定这是怎么回事。

I don't think this is the best fix for the application, and OverD gave a better solution. Will apply it eventually.

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