Rxswift: becomeFirstResponder() does not work when UITextField delegate is implemented

Created on 6 Jan 2016  Â·  5Comments  Â·  Source: ReactiveX/RxSwift

Hey,

I'm new to RxSwift and I was just playing around with the GitHubSignup example. I have now the problem that when I set the delegate from the UITextField's to self and add the following delegate method:

extension GitHubSignupViewController2: UITextFieldDelegate {
  func textFieldShouldReturn(textField: UITextField) -> Bool {
    if textField == usernameOutlet {
      passwordOutlet.becomeFirstResponder()
    }
    return true
  }
}

The passwordOutlet becomes the first responder for a millisecond and gets resigned immediately. Im now not quite sure why this happens and if it is on purpose.

Thanks!

Most helpful comment

Hi @svenbacia ,

I believe that if you play it dirty ...

extension GitHubSignupViewController2: UITextFieldDelegate {
    func textFieldShouldReturn(textField: UITextField) -> Bool {
        if textField == usernameOutlet {
            dispatch_async(dispatch_get_main_queue()) {
                self.passwordOutlet.becomeFirstResponder()
            }
        }
        return true
    }
}

... it does work.

If you do this

    override func viewDidLoad() {
        super.viewDidLoad()

        let viewModel = GithubSignupViewModel2(
            input: (
                username: usernameOutlet.rx_text.asDriver(),
                password: Driver.just("constant text"),
                repeatedPassword: repeatedPasswordOutlet.rx_text.asDriver(),
                loginTaps: signupOutlet.rx_tap.asDriver()
            ),
            dependency: (
                API: GitHubDefaultAPI.sharedAPI,
                validationService: GitHubDefaultValidationService.sharedValidationService,
                wireframe: DefaultWireframe.sharedInstance
            )
        )

        //// THIS CHANGES THE BEHAVIOR
        ///passwordOutlet.addTarget(self, action: "sayHiFromChanged", forControlEvents: [.AllEditingEvents])
    }
    func sayHiFromChanged() {

    }

... then your code also works. If you observe changes to text box in this way

passwordOutlet.addTarget(self, action: "sayHiFromChanged", forControlEvents: [.AllEditingEvents])

like we do internally, then your original code doesn't work again.

It seems to be like what you are doing is kind of hack because you are changing responder and performing side effects while text field is asking "can I stop editing", but can't say I haven't done similar things in past.

I believe that maybe you wanted to write this instead?

usernameOutlet.rx_controlEvent(.EditingDidEnd)
            .subscribeNext { [weak self] _ in
                self?.passwordOutlet.becomeFirstResponder()
            }
            .addDisposableTo(disposeBag)

¯_(ツ)_/¯

All 5 comments

Hi @svenbacia ,

I believe that if you play it dirty ...

extension GitHubSignupViewController2: UITextFieldDelegate {
    func textFieldShouldReturn(textField: UITextField) -> Bool {
        if textField == usernameOutlet {
            dispatch_async(dispatch_get_main_queue()) {
                self.passwordOutlet.becomeFirstResponder()
            }
        }
        return true
    }
}

... it does work.

If you do this

    override func viewDidLoad() {
        super.viewDidLoad()

        let viewModel = GithubSignupViewModel2(
            input: (
                username: usernameOutlet.rx_text.asDriver(),
                password: Driver.just("constant text"),
                repeatedPassword: repeatedPasswordOutlet.rx_text.asDriver(),
                loginTaps: signupOutlet.rx_tap.asDriver()
            ),
            dependency: (
                API: GitHubDefaultAPI.sharedAPI,
                validationService: GitHubDefaultValidationService.sharedValidationService,
                wireframe: DefaultWireframe.sharedInstance
            )
        )

        //// THIS CHANGES THE BEHAVIOR
        ///passwordOutlet.addTarget(self, action: "sayHiFromChanged", forControlEvents: [.AllEditingEvents])
    }
    func sayHiFromChanged() {

    }

... then your code also works. If you observe changes to text box in this way

passwordOutlet.addTarget(self, action: "sayHiFromChanged", forControlEvents: [.AllEditingEvents])

like we do internally, then your original code doesn't work again.

It seems to be like what you are doing is kind of hack because you are changing responder and performing side effects while text field is asking "can I stop editing", but can't say I haven't done similar things in past.

I believe that maybe you wanted to write this instead?

usernameOutlet.rx_controlEvent(.EditingDidEnd)
            .subscribeNext { [weak self] _ in
                self?.passwordOutlet.becomeFirstResponder()
            }
            .addDisposableTo(disposeBag)

¯_(ツ)_/¯

Thanks @kzaher for the clarification! Your proposed solution works as excepted. :)

I think we can close this one.

I have the same problem too. I'm using IQKeyboardManager library, it has a class IQKeyboardReturnKeyHandler which will handle all return presses to move onto next textfield. but the same thing as what @svenbacia said, happens

good

Was this page helpful?
0 / 5 - 0 ratings

Related issues

lyricsboy picture lyricsboy  Â·  3Comments

delebedev picture delebedev  Â·  3Comments

trant picture trant  Â·  3Comments

gaudecker picture gaudecker  Â·  3Comments

RobinFalko picture RobinFalko  Â·  3Comments