RIB Architecture in iOS Swift

Shilpesh S
Simform Engineering
8 min readDec 26, 2023

Understanding the business-driven architecture provided by Uber

As iOS developers, we are familiar with architectural patterns like MVVM, MVC, and VIPER that help organize code and enable better testing and scaling of apps. Recently, I came across an intriguing architecture called RIBs. In this post, I will provide an overview of RIBs — what they are, the core components, how they work, and why you may want to consider them for your next iOS project. RIBs originate from Uber Engineering as they found limitations with other iOS architectures when developing their large ride-sharing app. By the end, you’ll have a solid understanding of this unique architecture and whether it’s a good fit for your needs.

Table of Contents:

  • What is RIB
  • Why the need for RIB
  • How to use RIB architecture for your project
  • Pros and cons of RIB
  • References
  • Conclusion

What is RIB?

RIB stands for Router, Interactor, and Builder. Upon hearing these terms, confusion may arise regarding their purposes and requirements. Let’s delve into each of these keywords step by step to gain a clearer understanding.

  1. Router: A router facilitates navigation from one screen to another by means of attaching or detaching. Essentially, it is employed for transitions within the RIB architecture.
  2. Interactor: The most crucial term within RIB, the interactor serves as the focal point for business logic and networking activities. It can be considered the central component of the overall architecture.
  3. Builder: Serving as the initial phase of RIB, the builder is responsible for initializing a new RIB. During this phase, make sure to define the dependencies and components required for the builder to function effectively.

In addition, there’s an optional View and Presenter. These are simply used for showing things on the screen, like when you make a login RIB. In this case, the UI part goes into the View or Presenter. They work together with the Interactor, which takes care of networking and business logic. For instance, when the login is successful, the Interactor informs the router to move to the Success screen.

RIB Flow Model

Now that you have a basic understanding of the RIB architecture, let’s explore why this architecture is important and what purpose it serves.

Why the need for RIB?

RIB architecture is developed by Uber Engineers to overcome the following problems:

  • Reduce the complexity of the codebase as compared to the MVC pattern.
  • Offer an architecture that is business-driven as compared to view-driven, unlike the VIPER architecture.
  • Provide an architecture that supports cross-platform development so that it’s useful for all mobile developers, both Android and iOS.
  • Facilitate better code segregation for UI, business logic, and navigation.
  • Provide a reactive pattern instead of an interactive one.
  • Ensure better scalability for a complex project.

Now let’s understand how to use this architecture in our project.

How to implement the RIB architecture in your project

To help you understand, I’ll walk you through a demo of a news app built on the RIB architecture. This app utilizes a news API to display the current trending news.

In this tutorial, we’ll work with two RIBs: one for presenting a list of current news (News RIB) and another for displaying news details (Detail RIB). The final output will be as shown below.

[News App made with RIB.]
  • To work with RIB, start by installing it in your project using your preferred method, as outlined here: https://github.com/uber/RIBs#installation-for-ios. You can choose either Carthage or CocoaPods for installation.
  • Once RIB is installed, create separate RIBs for News and its Detail.
  • As mentioned earlier, a RIB consists of three components, so you’ll need to create specific files for each RIB. Here is a reference to illustrate the initial structure of a RIB:
RIBs File Structure
  • The above reference is for Detailnews RIB; the same RIB structure will be there for news listing.

Now, let’s understand what is the purpose of these files in the RIB architecture.

  • DetailNewsRouter: This file is crucial for navigation. Here, you can create and attach a new RIB.
  • DetailsNewsViewController: Handle UI-related tasks in this file. The view controller is interconnected with the interactor.
  • DetailNewsBuilder: Initialize this file when attaching the child to the parent. Define the view controller, interactor, and router specific to the RIB in this place.
  • DetailNewsInteractor: This file is the central part of the RIB architecture, connecting the router and view controller.

Now, let’s move on to understanding the codebase made with RIB to understand architecture better.

[NewsBuilder]

Understanding ListingViewBuilder in RIB

In the RIB architecture, the ListingViewBuilder plays a crucial role in building and configuring the components necessary for the Listing RIB. It is the first step whenever any new RIB is created from its Parent. Let's break down this code step by step:

  • ListingViewDependency: It defines a protocol that represents the dependencies required by the Listing RIB, such as any web services we need to perform for this RIB. In this case, it declares a dependency called newsNetworkService type NetworkService.
  • ListingViewComponent: This is a concrete implementation of the Component protocol that conforms to ListingViewDependency. It provides access to the newsNetworkService as a newsService property, establishing a connection with the declared dependency.
  • Builder Protocol: The ListingViewBuildable protocol is introduced, extending the Buildable protocol. It declares a method build(withListener:), which is responsible for creating and configuring the Listing RIB from its parent. In our case, it will be created from RootRIB’s Router, and the Listener will act as the Parent interactor.
  • ListingViewBuilder Class:ListingViewBuilder is a concrete class that implements the ListingViewBuildable protocol. It inherits from the Builder class, passing the ListingViewDependency as a generic parameter.
  • Initializer: The init(dependency:) method initializes the builder with its required dependencies. In this case, it receivesListingViewDependency as a dependency from its parent.
  • build(withListener:):The build(withListener:) method is where the Listing RIB is constructed from its parent RIB (as shown below). In our case, it will be created from RootRIB’s Router and the Listener will act as the Parent interaction.
let router = listBuilder.build(withListener: interactor)
  • The process begins by establishing a ListingViewComponent using its dependency, which, in our case, is the newsservice.
  • Then, it creates a ListingViewViewController, which represents the user interface for the Listing RIB.
  • An ListingViewInteractor is instantiated, passing in the viewController and the newsService from the ListingViewComponent.
  • The listener (typically the parent RIB) is set for the interactor.
  • Additionally, a DetailNewsBuilder is created, which will be used later to build the Detail RIB.
  • Finally, the ListingViewRouter is returned, which encapsulates the interactor, view controller, and the DetailNewsBuilder.

This code is a critical part of the RIB architecture as it establishes the foundation for creating and managing the Listing RIB, along with its associated dependencies and interactions. It ensures that the Listing RIB can function independently and be easily composed with other RIBs in our iOS application.

Now, let’s understand other components used in RIB.

Understanding ListingViewRouter RIB

[NewsRouter]
  • Router Definition: The ListingViewRouter is defined as a final class that conforms to the ViewableRouter protocol. It specifies that it's associated with ListingViewInteractable (Interactor) and ListingViewViewControllable(Controller).
  • Properties: The newsBuildableproperty represents a builder for the DetailNews RIB. It will be used to create instances of the DetailNews RIB when needed. ThedetailNewsRouterprivate property keeps a reference to the router of the DetailNews RIB, allowing you to manage the child RIB.
  • Initializer: The ListingViewRouter has an initializer that takes three parameters which are initialized at the time of builder formation:
  • interactor: This is an instance of ListingViewInteractable, which represents the Interactor associated with the Listing RIB.
  • viewController: This is an instance of ListingViewViewControllable, which represents the ViewController associated with the Listing RIB.
  • detailBuilder: This is an instance of DetailNewsBuilder, which will be used to create DetailNews RIBs.
  • Router Assignment: Within the initializer, the router assigns itself to the Interactor by setting interactor.router = self. This establishes a connection between the Router and the Interactor.
  • routeToDetail(for newsDetail:): This method is called when you want to navigate to the DetailNews RIB, typically when a user selects a news article, which is called when selection is done through the view controller’s news listing.
  • It first used newsBuildable to create a DetailNews RIB using build(withListener:newsDetail:). This method is responsible for constructing the DetailNews RIB and connecting it to the Listing RIB.
  • The attachChild(detailRouting) method is used to attach the DetailNews RIB as a child of the Listing RIB. This ensures proper management of the child RIB's lifecycle.
  • The detailNewsRouter property is updated to hold a reference to the DetailNews router, allowing you to interact with the child RIB.
  • Finally, the method calls viewController.pushViewController(detailRouting.viewControllable, animated: true) to present the DetailNews RIB's view on the screen.

Understanding ListingViewInteractor and Viewcontroller

  • Both components are interconnected, with the Interactor handling web services or networking tasks, and the ViewController updating the UI based on the response from these services.
  • Here, the view controller will act as a presenter for the interactor, and the interactor will act as a listener for the view controller.
  • Whenever the screen is loaded, we will ask for news data from the controller to the interactor in the following way:
self?.listener?.fetchNews(isRefresh: false)
  • In this context, the listener is our Interactor. Once this method is called, in our Interactor file, we will update the ViewController as follows:
 func fetchNews(isRefresh: Bool) {
if !isRefresh {
presenter.showActivityIndicator(true)
}
let params = [APIConstant.RequestParameters.country : APIConstant.RequestParameters.countryValue,
APIConstant.RequestParameters.apiKey : APIConstant.RequestParameters.apiKeyValue]
newsService.fetchNews(type: .newsFetch, parameters: params)
.done { [weak self] news in
self?.newsList.accept(news)
self?.presenter.showActivityIndicator(false)
NotificationCenter.default.post(name: NSNotification.refreshData, object: nil)
}
.catch { error in
self.presenter.showActivityIndicator(false)
self.presenter.showErrorAlert(error:error.localizedDescription)
}
.finally {
self.presenter.showActivityIndicator(false)
}
}
  • In the above code snippet, when we get the news list, we stop the indicator which is there in our view controller file (managed by the presenter), and reload the data in the view controller.
  • So, this is the basic concept of interaction between the view controller and interactor.

So that’s how RIB architecture will work for our project!

Pros and Cons of RIB

[Pros & Cons of RIB]

References

  1. Uber Engineering Blog:— “A New Architecture for the Uber Rider App”: This blog post discusses how Uber adopted the RIB architecture to improve modularity and scalability in their Rider app.
  2. GitHub — Uber/RIBs Repository: The official repository for Uber’s RIBs framework, containing source code, documentation, and resources for RIB architecture in iOS development.
  3. GitHub — Uber/RIBs Wiki: A comprehensive Wiki offering detailed documentation, guides, and tutorials on the RIB architecture, serving as a valuable reference for developers.

Conclusion

The RIB architecture is a powerful way for developers to build apps that are organized, easy to maintain, and can grow as needed. While it might take some time to learn and involve a bit of initial setup, the benefits, like well-structured code, easy testing, and the ability to expand your app’s features, make it a smart option.

Follow Simform Engineering to keep yourself updated with the latest trends in the technology horizon. Follow us: Twitter | LinkedIn

--

--