Skip to content

iOS Tutorial 1

Tuomas Artman edited this page May 11, 2018 · 22 revisions

Create your first RIB

Welcome to the tutorials, which have been designed to give you a hands-on walkthrough through the core concepts of RIBs. As part of the tutorials, you'll be building a simple TicTacToe game using the RIBs architecture and associated tooling.

We've provided you with a project that contains the boilerplate for a new RIBs application. You can find the source files here. Follow the README to install and open the project before reading any further.

Goal

The goal of this tutorial is to understand the various pieces of a RIB and, more importantly, how they interact and communicate with each other. At the end of this tutorial, we should have an app that launches into a screen where the user can type in player names and tap on a login button. Tapping the button should then print player names to the Xcode console.

Project structure

The boilerplate code that we provide contains an iOS project that consists of two RIBs. When the app launches, its AppDelegate builds a Root RIB and transfers control over the application to it. The purposes of the Root RIB are to serve as a root of the RIBs tree and to transfer control to its children when necessary. The Root RIB's code is mostly autogenerated by Xcode templates, understanding this code is not required for this exercise.

The second RIB in TicTacToe app is called LoggedOut, it should contain the login interface and manage authentication-related events. When the Root RIB gains control over the app from the AppDelegate, it immediately transfers it to the LoggedOut RIB to display the login form. The code responsible for building and presenting LoggedOut RIB is already provided and can be found in RootRouter.

For now, LoggedOut RIB is not implemented. If you open LoggedOut group, you'll only find a DELETE_ME.swift file with some stubs necessary to compile the code. In this tutorial, we will create a proper implementation of LoggedOut RIB.

Create LoggedOut RIB

Select New File menu item on the LoggedOut group.

Select the Xcode RIB templates.

Name the new RIB "LoggedOut" and check the "Owns corresponding view" checkbox.

It is not necessary for a RIB to have an own view(controller). However, we want to create a view controller for the LoggedOut RIB, because this RIB should contain an implementation of the login interface (i.e. text fields with the player names and a "Login" button). Checking "Owns corresponding view" checkbox ensures that the new RIB will be generated with a corresponding view controller class.

Create the files and make sure that they are added to the "TicTacToe" target and saved into the "LoggedOut" folder.

Now we can delete the DELETE_ME.swift file.

Understanding the generated code

image7

We have just generated all the classes that compose the LoggedOut RIB.

  • The LoggedOutBuilder conforms to LoggedOutBuildable so other RIBs that use the builder can use a mocked instance that conforms to the buildable protocol.
  • The LoggedOutInteractor uses the LoggedOutRouting protocol to communicate with its router. This is based on the dependency inversion principle where the interactor declares what it needs, and some other unit, in this case, the LoggedOutRouter, provides the implementation. Similar to the buildable protocol, this allows the interactor to be unit-tested. LoggedOutPresentable is the same concept that allows the interactor to communicate with the view controller.
  • The LoggedOutRouter declares what it needs from the LoggedOutInteractable to communicate with its interactor. It uses the LoggedOutViewControllable to communicate with the view controller.
  • The LoggedOutViewController uses LoggedOutPresentableListener to communicate with its interactor following the same dependency inversion principle.

LoggedOut UI

Below is the UI we want to build, so we'll need to modify the LoggedOutViewController. To save time, you can also use our code and add it to the LoggedOutViewController implementation.

Make sure to import SnapKit in the LoggedOutViewController if you're using the provided example code so that the project compiles.

Login logic

After the user taps "Login" button, the LoggedOutViewController will have to call its listener (LoggedOutPresentableListener) to notify it that the user wants to log in. The listener will have to receive the names of the players participating in the game to proceed with the login request.

To implement this logic, we will have to update the listener to let it receive the login request from the view controller.

Modify the LoggedOutPresentableListener protocol in the LoggedOutViewController.swift file to be the following:

protocol LoggedOutPresentableListener: class {
    func login(withPlayer1Name player1Name: String?, player2Name: String?)
}

Notice that both player names are optional, since the user may not enter anything for the player names. We could disable the Login button until both names are entered, but for this exercise we’ll let the LoggedOutInteractor handle the empty names. If player names are empty, we'll default them to "Player 1" and "Player 2" in the implementation.

Now, modify LoggedOutInteractor to conform to the modified LoggedOutPresentableListener protocol by adding the following methods:

// MARK: - LoggedOutPresentableListener

func login(withPlayer1Name player1Name: String?, player2Name: String?) {
    let player1NameWithDefault = playerName(player1Name, withDefaultName: "Player 1")
    let player2NameWithDefault = playerName(player2Name, withDefaultName: "Player 2")

    print("\(player1NameWithDefault) vs \(player2NameWithDefault)")
}

private func playerName(_ name: String?, withDefaultName defaultName: String) -> String {
    if let name = name {
        return name.isEmpty ? defaultName : name
    } else {
        return defaultName
    }
}

For now, when the user logs in we'll just print out the user names.

Finally, we'll hook up our view controller to call the listener method when the login button is pressed. In LoggedOutViewController.swift, change the didTapLoginButton method (in case you used our UI code) to the following implementation:

@objc private func didTapLoginButton() {
    listener?.login(withPlayer1Name: player1Field?.text, player2Name: player2Field?.text)
}

Tutorial complete

Congratulations! You have just created your first RIB. If you build and run the project now, you'll see the login interface with an interactive button. After tapping the button, you'll see player names printed in the Xcode console.

To recap, in this tutorial we have generated a new RIB from the Xcode template, updated its interface and added a handler for the button tap event that forwards the data entered by the user from the view controller to the interactor. This allows us to separate the responsibilities between these two units and improve the testability of the code.

Now onwards to tutorial 2.

Once you've read through the documentation, learn the core concepts of RIBs by running through the tutorials and use RIBs more efficiently with the platform-specific tooling we've built.

Tutorial 1

iOS, Android

Tutorial 2

iOS, Android

Tutorial 3

iOS, Android

Tutorial 4

iOS, Android

Tooling

iOS, Android

Clone this wiki locally