By Mauricio Cousillas

At Moove It we work hard to create beautiful, scalable and maintainable iOS apps. To achieve this, we have tried different architectures over time, such as the classic Model View Controller (MVC); View, Interactor, Presenter, Entity and Router (VIPER); Model View Presenter (MVP); and Model–View–ViewModel (MVVM). We have also tried several third party-frameworks, which all come with their advantages and disadvantages.

We wanted to define a baseline for any new project, using all our previous experience to streamline and reduce the number of decisions that a developer has to make before beginning to develop a new project. With that in mind, we defined a project template that works as a starting point for iOS applications; providing a base architecture, core frameworks, and helpers to jumpstart development.

In this blog post, we introduce the fundamental concepts and tools included in the project. If you just want to check out the code, you can go directly to our GitHub repo and access the template.

Download template

Base tooling

The following list includes all of the basic frameworks that come bundled with the project and their purposes:

  • R.Swift is used for xcode asset management
  • SwiftLint is used for style checking
  • RxSwift is used for data flow management
  • Alamofire + Moya/Rx are used for networking
  • RealmSwift + RxRealm are used for database management
  • Whisper is used for in app notification-style messages

Architecture

We are going to use MVVM + routers (R), but with some caveats:

Architecture

Models

The models won’t store business logic. They will only act as data stores (Realm objects when using a local database, and Structs in other cases).

Views

The responsibility of Views (or ViewControllers in this case) is to display the data provided by its ViewModel and forward all events to their respective ViewModel.

ViewModel

The ViewModel is the component in charge of managing the state of each view and any processing necessary for the displayed or submitted data. Moreover, the ViewModel communicates with Controllers to fetch the data necessary for its view, and uses the Router to forward navigation actions.

Controllers, Services and DataManagers

The Controllers are in charge of managing the Models. This means that ideally you should have one Controller per Model(unless you need something like a session controller that can manage more than one model such as a user model) and another model for storing session information.

The Controllers use two types of support classes; Services and DataManagers for networking access and database access, respectively. If you don’t have one of them (for example apps that only consume API data and save nothing locally), you can replace your Controller with a Service or a DataManager and use that directly in your ViewModel.

Router

The router is the component in charge of handling the navigation stack for your entire application. For this, the router keeps track of your rootViewController and your currentViewController (the one currently visible).

To keep everything tidy and isolated, the router does not know how to instantiate the screens that it presents. This is defined separately using the Route protocol. A Route is a component that encapsulates all of the necessary logic to instantiate a view, with its corresponding viewModel and any other parameters forwarded from other routes. Apart from the Route, you can set a TransitionType when you navigate to a route. This tells the navigator how the screen should be presented (modally, pushed, resetting the stack, etc.).

So, to call a navigation action, all you need to do is call your Application’s Router and call .navigate with the corresponding Route and TransitionType.It’s as simple as that!

Usage

Option #1: Copy the core files to your project

If you already have a running project and you want to use this project’s core modules, you can simply copy the source files into your project. Those are available in the /Core folder. This can come in handy with projects where you want to start by refactoring some parts of the code instead of starting from scratch.

Option #2: Start from scratch

  1. Clone this repository to your machine.
  2. Change the git project remote URL to one of your own with git remote set-url origin https://github.com/USERNAME/REPOSITORY.git.
  3. Make all of the following scheme, target and ID changes, to update the necessary information about your new app.
    • Change all schemes to be named after your new project.
    • Change the bundle ID to one of your own.
    • Set up certificates (or let xcode do it automatically).
    • Update the TargetType+BaseProject.swift to be named after your project.
    • Check the Constants.swift file and update the baseUrl properties to point to your backend services.
  4. Go to your Podfile and change the target names to the new ones that you have set up.
  5. Run pod repo update and pod install.
  6. Build both targets to confirm that everything is running properly.

Configuring Environments

We’ve all faced the same problem when defining production and development constants, such as the API URL, setting up crash logging only in production, etc. Here at Moove It, we decided to use two separate build targets, Production and Development, to differentiate between these two environments.

Using different build targets allows us to use Build Flags to see in which environment we are running. If you don’t know how to set up new Build Flags on your project, a detailed step-by-step guide may be found in this article . Additionally, running two separate targets of your app has other advantages, such as the ability to release both separately and having better management of early access for each environment. If you want to dive deeper into the topic, you can read this post which shows how to set up your targets and what can you do with them.

Conclusions

We have defined a starting point for any iOS project that we could imagine. Having a standard for any project is always an advantage, both for developers starting work on a project from scratch, as well as for newcomers who diving into a pre-existing project. It’s always easier to step into a project knowing where everything should be, which frameworks are being used, and other basic development information.

One question that we asked ourselves while building this was: Can we use this for any type of software project. The answer is yes! One of our main goals was to keep this project as small and flexible as possible so that it could be used in as many cases as possible – and we succeeded. We hope it helps you succeed too!