3
\$\begingroup\$

On an authentication view, there are some inputs, like password, email, etc and a sign up button which is enabled only if theses inputs are not empty.

So what I have is this function:

func canSignUpButtonBeEnabled() -> Bool {

    let password = self.passwordTextField.text.stringByReplacingOccurrencesOfString(" ", withString: "")

    return (!self.emailTextField.text.isEmpty && !self.passwordTextField.text.isEmpty
            && !self.firstNameTextField.text.isEmpty  && !self.lastNameTextField.text.isEmpty
            && countElements(password) >= 4)

}

And after each character entered by the user, I set on the enable property of my button the result of this function.

So I was wondering if there is a cleaner solution to do it?

\$\endgroup\$
3
  • \$\begingroup\$ If there is no parameters you should use a read-only computed property \$\endgroup\$
    – Leonardo Savio Dabus
    Commented Feb 14, 2015 at 19:48
  • \$\begingroup\$ btw there is no need to use self most of the time. you can always omit it and if needed Xcode will suggest adding it for you. \$\endgroup\$
    – Leonardo Savio Dabus
    Commented Feb 14, 2015 at 19:51
  • 3
    \$\begingroup\$ @LeonardoSavioDabus I prefer use it, it remind me if the property is an attribute of my class or not \$\endgroup\$
    – user65152
    Commented Feb 14, 2015 at 20:06

3 Answers 3

1
\$\begingroup\$

You bind password but then in your return logic you use self.passwordTextField.text.isEmpty which seems to be wrong - but would get caught by countElements(password) >= 4 later.

This would be arguably more readable, and perhaps modular, if you introduced intermediate predicates. Like such:

class Whatever {

  func hasName () -> Bool {
    return !self.firstNameTextField.text.isEmpty  &&              
           !self.lastNameTextField.text.isEmpty
  }

  func hasEmail () -> Bool { 
    return !self.emailTextField.text.isEmpty
  }

  func hasValidPassword () -> Bool {
    let password = self.passwordTextField.text.stringByReplacingOccurrencesOfString(" ", withString: "")
    return countElements(password) >= 4
  }

  func canSignUpButtonBeEnabled() -> Bool {
    return hasEmail() && hasName() && hasValidPassword()
  }
}
\$\endgroup\$
1
  • \$\begingroup\$ Seeing like that, yes, that's much more clear ! \$\endgroup\$
    – user65152
    Commented Feb 15, 2015 at 20:42
0
\$\begingroup\$

According to Clean Code, the only thing that you might can do, is to create a variable from what you return, for example:

func canSignUpButtonBeEnabled() -> Bool {

    let password = self.passwordTextField.text.stringByReplacingOccurrencesOfString(" ", withString: "")
    let canSignUpButtonEnabled = (!self.emailTextField.text.isEmpty && !self.passwordTextField.text.isEmpty
        && !self.firstNameTextField.text.isEmpty  && !self.lastNameTextField.text.isEmpty
        && countElements(password) >= 4)
    return canSignUpButtonEnabled 
}

This way it is a little bit cleaner. And that is useful also in if statements to name your expressions in order to be clearer that what is the if statement is about.

\$\endgroup\$
0
\$\begingroup\$
let password = self.passwordTextField.text.stringByReplacingOccurrencesOfString(" ", withString: "")

From a user experience point of view, this is almost certainly not what you want. You're allowing the user to enter spaces in the password field, yet this logic indicates that spaces are not allowed in the password.

Moreover, you're almost certainly duplicating this logic in the method in which you actually attempt to login, correct? What would be more appropriate would be to override the text field delegate method shouldChangeCharactersInRange: and prevent spaces from ever being entered in the first place.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.