Chapter 3, Challenge 2

Just a small quibble…

The signature of the login function is this:

func logInWith(username: String, password: String, completion: (Error?) -> Void)

This implies to me that the completion handler will always be called. If things go well and the login is successful, then the Error parameter will be nil, but if the login fails, then the Error parameter will hold the corresponding Error object. In the solution code provided for this challenge, the function only calls the completion handler in the second case, that is, when there is an error.

func logInWith(username: String, password: String, completion: (Error?) -> Void) {
    guard username == "johnny@appleseed.com", password == "appleseed" else {
        completion(LoginError.invalidCredentials)
        return
    }

    // Update userSession
    userSession.value = .loggedIn
}

Shouldn’t the completion handler be updated in the case of success? Like this:

    func logInWith(username: String, password: String, completion: (Error?) -> Void) {
        guard username == "johnny@appleseed.com", password == "appleseed" else {
            completion(LoginError.invalidCredentials)
            return
        }

        // Update userSession
        completion(nil) // <-- add this line
        userSession.value = .loggedIn
    }

Or don’t we care about this since we’ll already get a callback to the onNext handler of the subscriber to userSession?

I would say the completion should be called otherwise the line print("User logged in.") in the for-loop will never be executed. I think it would be better to put completion(nil) in the last line so the correct state .loggedIn is already set.

1 Like

I also found this problem. I think this was a mistake

1 Like