Previous Lecture Complete and continue  

  Lecture 15. Authentication with Firebase - Signing In User

Homework to Make Sense of The Lecture and Dig Deeper

Exercise 1.

At 5:47, why should we use the segue from the Sign In View Controller instead of from the Sign In Button as before? Hint: who initiates this segue?

To verify that what we did is correct, create a segue from the Sign In Button instead. What would happen in this case?

Exercise 2.

How can we delay the execution of a function or method named scheduledMethod() 3 seconds

Hint: The Timer.scheduledTimer(withTimeInterval: , repeats: , block: ) method might be helpful.

Exercise 3

viewDidLoad() vs viewDidAppear()

Suppose that you want to bypass the authentication process, and want the app to switch to the tab bar controller right after the app is open. For example, when users turned off the app without logging out, you would want to bypass the sign in process when the users open the app again.

Suppose that the Sign In View Controller is the Initial View Controller of the Main Interface of the app, meaning it will show up first when we open the app. Instead of searching online for a solution, you decide to perform some experiments to come up with an answer yourself.

(a) At first, you think that it’s a reasonable idea to perform the switching segue in the viewDidLoad() method of the Sign In View Controller:

self.performSegue(withIdentifier: "signInToTabbarVC", sender: nil)`

What do you observe?

(b) Something unexpected just happened, and you decided to dig a little more. You decided to print something out right before and after that command to make sure the code is still running fine.

print("This will always be printed out.")
self.performSegue(withIdentifier: "signInToTabbarVC", sender: nil)
print("Something is wrong if this is printed out.")

What do you see this time?

(c) There’s definitely wrong with the code. You reckon that the targeted command is probably executed at a wrong time or a wrong place. To make sure, you decided to keep it at the same place where it currently is, but change the time when it is executed. Use the `Timer.scheduledTimer` in Exercise 2 to delay executing this switching task for two seconds. What happen in this case?

(d) Now you reckon that performing this segue in the `viewDidLoad()` is probably not a good idea. Read the reference of the viewDidLoad() method and in one sentence, explain what have been happening so far.

Hint: what type of segue we’re using?

(e) Delaying the segue execution for two seconds, which is a significant amount of time, makes it work. This suggests that during that two second period, some methods, other than viewDidLoad() of the Sign In View Controller were executed. Therefore, you decided to perform this segue in a few different methods of the Sign In View Controller. Which one do you think is the best choice? Hint: A view might not be able to present another view if it wasn’t visible

Exercise 4.

In the lecture, in the Sign In View Controller, we performed text field checking by calling the textFieldDidChange() method of the Sign Up View Controller on the Sign In View Controller instance:

func handleTextField() {
  emailTextField.addTarget(self, action: #selector(SignUpViewController.textFieldDidChange), for: UIControlEvents.editingChanged)
  passwordTextField.addTarget(self, action: #selector(SignUpViewController.textFieldDidChange), for: UIControlEvents.editingChanged)
}

In the reference of the .addTarget() method, the target parameter is defined as “The target object—that is, the object whose action method is called.” This mean the action we used should’ve been the one of the Sign In View Controller:

#selector(SignInViewController.textFieldDidChange)`

However, this feature still worked fine. We reckon that Xcode tried to clear the confusion by matching up the textFieldDidChange() method from the methods of the Sign In View Controller. To confirm if this is the case, let’s perform some experiments.

(a) To see that Xcode will find the used action from the methods of the Sign In View Controller, define a method called test() in the Sign Up View Controller:

func test() { print(“Printed from the Sign Up View Controller.”) }

Now, in the Sign In View Controller, in the .addTarget() method of the emailTextField, use this test() method from the Sign Up View Controller:

func handleTextField() {
  emailTextField.addTarget(self, action: #selector(SignUpViewController.test), for: UIControlEvents.editingChanged)
  ...
}

Run the app then edit the the email text field of the Sign In View. What do you observe?

(b) Now create ambiguity by defining a method with the same name test() in the Sign In View Controller, but with a different implementation.

func test() { print(“Printed from the Sign In View Controller.”) }

These two test() methods are used to signal what were called.

Re-run the app again. What was printed out in the console? Is it consistent with what we do in the lecture?

(c) What is a good alternative way to add action in this case to avoid such ambiguity?

Exercise 5.

Can we safely unwrap the text field content in this case?

@IBAction func signInButton_TouchUpInside(_ sender: Any) {
  FIRAuth.auth()?.signIn(withEmail: emailTextField.text!, password: passwordTextField.text!, completion: { (user, error) in
    if error != nil {
      print(error!.localizedDescription)
      return
    }
    self.performSegue(withIdentifier: "signInToTabbarVC", sender: nil)
  })
}

Exercise 6.

First Responder

The sign in feature is working great now, and you decide to test the app on a real device. If you don’t have a real one, you can easily pretend to run the app on one by running the app then uncheck the Connect Hardware Keyboard option under Hardware → Keyboard of the Simulator. Then if you touch a text field to start editing it, a keyboard will display for typing in the input.

You now realize a problem. If you change your mind and want to switch to the sign up view, you can’t dismiss the keyboard to reach the switching button. You decide to sit down and do some work to dismiss the keyboard.

To know how to dismiss the keyboard, you realize that you must understand why there is a keyboard in the first place. In particular, you’d like to find out why touching a text field makes the keyboard display. Moreover, is there any way to display the keyboard without touching the text field? After a few searching attempts, you reckon that the concept first responder might be the key in this case. Thus, your first goal is to understand this term.

(a) Comment out everything in the body of the signInButton_TouchUpInside(), then make the sign in button trigger the first responder status of the emailTextField.

@IBAction func signInButton_TouchUpInside(_ sender: Any) {
  emailTextField.becomeFirstResponder()
}

What can we say about this phenomenon? Is what you see similar to a touch on the email text field?

(b) Now let's find out what happen when users touch the email text field.

func emailTextField.addTarget(self, action: #selector(SignInViewController.textFieldDidBegin), 
                              for: UIControlEvents.editingDidBegin)

Then define

func textFieldDidBegin() {
  if emailTextField.isFirstResponder == true {
    print("Email text field is the first responder")
  }
}

This means touches trigger first responder status. Therefore, touches trigger first responder status, which in turn triggers the keyboard. What is your idea to dismiss keyboards?

Exercise 7.

First Responder - continued

How to automatically focus on the email text field and display the corresponding keyboard when the app runs?

Exercise 8.

Closure

In the below function call, is the timer parameter of the block input necessary? If not, what can it be replaced by?

Timer.scheduledTimer(withTimeInterval: 2, repeats: false, block: { (timer) in
  self.performSegue(withIdentifier: "signInToTabbarVC", sender: nil)
    print("This should be printed last.")
})

Exercise 9.

Keyboard covers sign in button

If you build the app on small screen devices like iPhone 5, and start editing the email text field on the Sign In View, the sign in button will be hidden under the keyboard. What is your idea to fix this issue? Write a meta pseudo-code snippet express your proposed solution.

Download
Discussion
17 comments