Login Screen Implementation

We will look into the login screen implementation. This screen is implemented in the LoginViewController.swift file and the LoginViewController.m file.

The login screen is configured to open as the first screen in the navigation controller in the storyboard.

Screen components are associated with the implementation of the class via the storyboard as below:

  • The two text fields are associated with the usernameField and passwordField properties of the LoginViewController class by outlets.

  • The button actions are set to the signupButtonPressed(_:) and loginButtonPressed(_:) methods.

  • The activity indicator is associated with activityIndicator by an outlet to control animation while waiting (Details of the activity indicator is not covered in this tutorial).

  • The tap gesture recognizer is connected to the onTap(_:) method so that the keyboard will be hidden when the screen is tapped. This method handles the process of ending edits.

  • The manual segue, OpenMainPage is set so that the user program can open the data listing screen.

Creating a user

We will start with the user creation. When the "Sign Up" button is tapped, the signupButtonPressed(_:) method is executed. The following sample code is an excerpt from this method (note that the excerpt is simplified).

  • let username = usernameField.text!
    let password = passwordField.text!
    
    // Create a KiiUser object.
    let user = KiiUser(username: username, andPassword: password)
    
    // Register the user asynchronously.
    user.performRegistration { (user, error) -> Void in
      if error != nil {
        self.showMessage("Sign up failed", error: error as NSError?)
        return
      }
    
      // Go to the main screen.
      self.performSegue(withIdentifier: "OpenMainPage", sender: nil)
    }
  • NSString *username = self.usernameField.text;
    NSString *password = self.passwordField.text;
    
    // Create a KiiUser object.
    KiiUser *user = [KiiUser userWithUsername:username
                                  andPassword:password];
    
    // Register the user asynchronously.
    [user performRegistrationWithBlock:^(KiiUser *user, NSError *error) {
      if (error != nil) {
        [self showMessage:@"Sign up failed" error:error];
        return;
      }
    
      // Go to the main screen.
      [self performSegueWithIdentifier:@"OpenMainPage" sender:nil];
    }];
  1. The username and password are taken from the screen using the UIKit framework of iOS. They are set in username and password, respectively.

  2. The username and password are passed to create a KiiUser instance on memory.

  3. The performRegistration(_:) method is called. The SDK sends a request to Kii Cloud to create the specified user.

Non-blocking API

The API that communicates with the server, like the performRegistration(_:) method, is implemented as the non-blocking API. In iOS mobile apps, the main thread manages the user interface process. The whole mobile app will freeze if the main thread starts waiting for network communication to finish. The non-blocking API is designed to solve this problem by not waiting for the network communication to finish.

The blocking API, on another hand, will wait for the API execution to finish. The blocking API is to be used when you are creating a worker thread by yourself and executing the API from this thread. For most APIs, both blocking and non-blocking APIs are available. We present the sample code for both APIs in our programming guide.

The following sequence diagram illustrates how the non-blocking API works.

When the main thread calls the performRegistration(_:) method, the SDK creates a worker thread internally and the method instantly returns control. The user can operate the screen while the network access process is ongoing, because the network call is made within the worker thread.

When the network call is finished and the next cycle of event processing starts, the main thread calls a closure for Swift or a block for Objective-C as the callback. Therefore, you do not need to worry about the thread synchronization in the callback.

Execution sequence

Be careful about the execution sequence.

  • // Step 1
    user.performRegistration { (user, error) -> Void in
      // Step 3
    }
    // Step 2
  • // Step 1
    [user performRegistrationWithBlock:^(KiiUser *user, NSError *error) {
      // Step 3
    }];
    // Step 2
     

In the above sample code, the place labeled as Step 3 is where you should write logic to be executed after the performRegistration(_:) method is executed. The performRegistration(_:) method is not yet complete when the place labeled as Step 2 is reached. If you write logic to be executed after the user registration in Step 2 by mistake, you will most likely encounter an error because the user registration process has just started.

When you are executing multiple APIs sequentially, you will need to write logic inside callback functions. This will make deeply nested code and make the code hard to read. To ensure code readability, you might use workarounds such as creating a worker thread by yourself and using the blocking API.

Execution result

You write logic to handle execution results inside the closure.

See the sample code in the programming guide to understand methods and classes to use in calling APIs. The below steps show how to write your code.

Once again, here is an excerpt of the user registration logic:

  • // Register the user asynchronously.
    user.performRegistration { (user, error) -> Void in
      if error != nil {
        self.showMessage("Sign up failed", error: error as NSError?)
        return
      }
    
      // Go to the main screen.
      self.performSegue(withIdentifier: "OpenMainPage", sender: nil)
    }
  • // Register the user asynchronously.
    [user performRegistrationWithBlock:^(KiiUser *user, NSError *error) {
      if (error != nil) {
        [self showMessage:@"Sign up failed" error:error];
        return;
      }
    
      // Go to the main screen.
      [self performSegueWithIdentifier:@"OpenMainPage" sender:nil];
    }];

When handling the API execution result, you need to check if there is any exception thrown. Non-blocking API execution will trigger network communication, so there is always a chance of error, such as a network error, to be caused. This applies to all non-blocking APIs, not only to the performRegistration(_:) method.

In Hello Kii, we handle the result as follows:

  • When the execution succeeded

    If the variable error is nil, the execution was successful. The user is registered and logged in.

    The OpenMainPage segue brings the data listing screen up.

    The state of the logged-in user is stored in a static variable within the SDK. You can use this variable in the data listing screen.

  • When the execution failed

    If the variable error is not nil, the variable stores an exception thrown in the SDK. We get the message with the showMessage(_:error:) method and show the message on the screen.

    The Kii Cloud SDK allows you to handle individual error cases by getting the error code from the code property of the variable error and the error message from the description key of the userInfo property. The showMessage(_:error:) method implemented in the UIViewController+Alert class gets the error message from the description key of the userInfo property and displays it on the screen.

Login

The implementation of the login process is almost the same as that of the user registration.

When the "Login" button is tapped, the loginButtonPressed(_:) method is executed. The following sample code is an excerpt from this method.

  • let username = usernameField.text!;
    let password = passwordField.text!;
    
    // Authenticate the user asynchronously.
    KiiUser.authenticate(username, withPassword: password) { (user, error) -> Void in
      if error != nil {
        self.showMessage("Login failed", error: error as NSError?)
        return
      }
    
      // Go to the main screen.
      self.performSegue(withIdentifier: "OpenMainPage", sender: nil)
    }
  • NSString *username = self.usernameField.text;
    NSString *password = self.passwordField.text;
    
    // Authenticate the user asynchronously.
    [KiiUser authenticate:username
             withPassword:password
                 andBlock:^(KiiUser *user, NSError *error) {
      if (error != nil) {
        [self showMessage:@"Login failed" error:error];
        return;
      }
    
      // Go to the main screen.
      [self performSegueWithIdentifier:@"OpenMainPage" sender:nil];
    }];

Just like the user registration logic, we get the username and password from the screen.

Then, we pass these values to the authenticate(_:withPassword:_:) method of the KiiUser class and start the login process. If the username and password are valid, the mobile app will be in the logged-in state.

The authenticate(_:withPassword:_:) method is a non-blocking API that causes network communication, so we write logic to process the result in the closure.

  • When the execution succeeded

    If the variable error is nil, the login is successful. The OpenMainPage segue brings the data listing screen up.

    The state of the logged-in user is stored in a static variable within the SDK. You can use this variable in the data listing screen.

  • When the execution failed

    If error is not nil, as with the case of failed user registration, an error message is displayed.

Current user

As already mentioned, once the user is logged in or successfully registered, the login state of this user will be kept in the SDK as the "current user". You can get the current user as follows:

  • let user = KiiUser.current()
  • KiiUser *user = [KiiUser currentUser];

This user is the one that you get as the argument user of the callback in the login method.

Once you have the user, you can make various operations like accessing buckets of this user's scope.

If you restart the mobile app, you need to log in to the mobile app again.


What's next?

We will explore how the data listing screen is implemented. We will check how the data registration and retrieval are handled.

Go to Data Listing Screen Implementation.

If you want to learn more...