-
Notifications
You must be signed in to change notification settings - Fork 905
iOS Tutorial 1
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.
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.
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.
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.
We have just generated all the classes that compose the LoggedOut
RIB.
- The
LoggedOutBuilder
conforms toLoggedOutBuildable
so other RIBs that use the builder can use a mocked instance that conforms to the buildable protocol. - The
LoggedOutInteractor
uses theLoggedOutRouting
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, theLoggedOutRouter
, 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 theLoggedOutInteractable
to communicate with its interactor. It uses theLoggedOutViewControllable
to communicate with the view controller. - The
LoggedOutViewController
usesLoggedOutPresentableListener
to communicate with its interactor following the same dependency inversion principle.
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.
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)
}
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.
Copyright © 2017 Uber Technologies Inc.
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.