Class Variable delayed stored


(jason bronson) #1

I have this class I wrote which stores the error messages from the
firebaseauth if a error occurs.
The problem is that the variable on first return is not set and on second
return is.
variable _errorMsg is empty on first return of method registerUser

Why is it not storing the variable when it's initially triggered?

//

// Authentication.swift

import Firebase

import FirebaseAuth

import FBSDKCoreKit

import FBSDKLoginKit

class Authentication: UIViewController {

    public var _errorMsg: String = ""

    private var createdUser: Bool!

    private var _userSignedIn = false

   /**

    * Registers a user using email/password method

    */

    func registerUser(email : String, password: String) -> Bool{

        createdUser = false

        FIRAuth.auth()?.createUser(withEmail: email, password: password,
completion: {(user, error) in

            if error != nil {

               if let errCode = FIRAuthErrorCode(rawValue: (error?._code)!)
{

                switch errCode {

                    case FIRAuthErrorCode.errorCodeInvalidEmail:

                        self._errorMsg = "Invalid Email"

                        print("DEBUG: invalid email")

                    case FIRAuthErrorCode.errorCodeEmailAlreadyInUse:

                        self._errorMsg = "Email already in use"

                        print("DEBUG: in use")

                    case FIRAuthErrorCode.errorCodeWeakPassword:

                        self._errorMsg = "Enter a stronger password"

                        print("DEBUG: stronger password")

                    default:

                        print("DEBUG: Create User Error: ")

                        self._errorMsg = "Unknown Error "

                   }

                }

                print("DEBUG: New user failed to create")

            }else{

                print("DEBUG: New user created ")

                self.createdUser = true

            }

        })

        return self.createdUser

    }

   /**

    * Registers a user using facebook login method

    */

    func facebookLogin() -> Bool{

        let facebookLogin = FBSDKLoginManager()

        facebookLogin.logIn(withReadPermissions: ["email"], from: self){
(result, error) in

            if error != nil {

                print("DEBUG: Unable to authenticate with Facebook \(error)"
)

            }else if result?.isCancelled == true {

                print("DEBUG: User cancelled authenticate with Facebook \(
error)")

            }else {

                print("DEBUG: User success")

                let credential =
FIRFacebookAuthProvider.credential(withAccessToken:
FBSDKAccessToken.current().tokenString)

                self.firebaseAuth(credential)

            }

        }

        return _userSignedIn

    }

   /**

    * Authentication through firebase

    * @parameter credential

    */

    func firebaseAuth(_ credential: FIRAuthCredential){

        FIRAuth.auth()?.signIn(with: credential, completion: {(user, error)
in

            if error != nil {

                print("DEBUG: Failed auth with Firebase \(error)")

                self._userSignedIn = false

            }else{

                print("DEBUG: Success auth with Firebase")

                self._userSignedIn = true

            }

        })

    }

    /**

     * Checks if the user is already signed in and sets the variable.

     */

    func signedIn() -> Bool {

        if ((FIRAuth.auth()?.currentUser) != nil) {

            print("DEBUG: user is signed in")

            _userSignedIn = true

        }

        return _userSignedIn

    }

   /**

    * Stores the error messages for authentication issues

    */

    var errorMsg: String {

        get{

            return _errorMsg

        }

        set(value){

            _errorMsg = value

        }

    }

}


(Fritz Anderson) #2

I assume you are talking about this function, which I’ll elide for purposes of discussion:

···

On 3 Oct 2016, at 5:46 PM, jason bronson via swift-users <swift-users@swift.org> wrote:

I have this class I wrote which stores the error messages from the firebaseauth if a error occurs.
The problem is that the variable on first return is not set and on second return is.
variable _errorMsg is empty on first return of method registerUser

Why is it not storing the variable when it's initially triggered?

===
func registerUser(email : String, password: String) -> Bool{
    createdUser = false
    
    FIRAuth.auth()?.createUser(withEmail: email, password: password, completion: {(user, error) in
        if error != nil {
            // ...
        }else{
            print("DEBUG: New user created ")
            self.createdUser = true
        }
    })
    
    return self.createdUser
}

The error parameter to the closure; the nature of the task, which must surely involve turnaround from another process or host; and the compiler error telling you (I’m betting) to refer explicitly to self in the closure; are a tipoff that the closure escapes. Escaping closures do not return to the code that presented them (or they don’t promise to; see below). createUser(withEmail:password:completion:) merely registers your completion (result) handler; it does not execute it; it waits in the background until the remote process responds. registerUser(... proceeds while createUser(... waits.

Upon the first call with that email/password combination., none of the code in your closure — including the part that sets self.createdUser to true — will have run by the time you return self.createdUser. By the end of registerUser(..., createdUser is still false.

---

As for the second return I’m guessing something like this: createUser(... caches the success of the last time it executed with that email/password pair. It sees there’s no need for a round trip through the external process, so it executes the completion closure immediately, with error == nil. The closure sets self.createdUser = true before it returns to your function. Your function returns the true.

  — F


(jason bronson) #3

Thanks I'll need to find another method for handling the asynchronous
delays.

···

On Tuesday, October 4, 2016, Fritz Anderson <fritza@manoverboard.org> wrote:

On 3 Oct 2016, at 5:46 PM, jason bronson via swift-users < > swift-users@swift.org > <javascript:_e(%7B%7D,'cvml','swift-users@swift.org');>> wrote:

I have this class I wrote which stores the error messages from the
firebaseauth if a error occurs.
The problem is that the variable on first return is not set and on second
return is.
variable _errorMsg is empty on first return of method registerUser

Why is it not storing the variable when it's initially triggered?

I assume you are talking about this function, which I’ll elide for
purposes of discussion:

===
func registerUser(email : String, password: String) -> Bool{
    createdUser = false

    FIRAuth.auth()?.createUser(withEmail: email, password: password,
completion: {(user, error) in
        if error != nil {
            // ...
        }else{
            print("DEBUG: New user created ")
            self.createdUser = true
        }
    })

    return self.createdUser
}

The error parameter to the closure; the nature of the task, which must
surely involve turnaround from another process or host; and the compiler
error telling you (I’m betting) to refer explicitly to self in the
closure; are a tipoff that the closure escapes. Escaping closures do not
return to the code that presented them (or they don’t promise to; see
below). createUser(withEmail:password:completion:) merely registers your
completion (result) handler; it does not execute it; it waits in the
background until the remote process responds. registerUser(... proceeds
while createUser(... waits.

Upon the first call with that email/password combination., none of the
code in your closure — including the part that sets self.createdUser to
true — will have run by the time you return self.createdUser. By the end
of registerUser(..., createdUser is still false.

---

As for the second return I’m guessing something like this: createUser(...
caches the success of the last time it executed with that email/password
pair. It sees there’s no need for a round trip through the external
process, so it executes the completion closure immediately, with error ==
nil. The closure sets self.createdUser = true before it returns to your
function. Your function returns the true.

— F

--
Sent from Gmail Mobile