Cocoa Touch Static Library vs. Cocoa Touch Framework

At AddThis we have the best geeks on the planet, and it’s our duty to share their knowledge and passion with the world. From time to time we hand the reins over to one of our teammates in a series we call, Talk Nerdy to Me.

Principal Software Engineer Kirk Elliott’s first post, 7 Things to Consider When Making iOS and Android Apps with Cordova or PhoneGap, got a lot of love, so we’re excited to have him back. Kirk enjoys DJing in the Baltimore Club Music scene, tidy code frameworks, and definitely being called Cappin’ Kirk by his co-workers.

  • Should you use a Framework or a Static Library?
  • Can you use Swift or Objective-C?
  • How can you export your final builds?
  • How will you provide instructions to use your library in a manner that will be easy to understand?

This post will attempt to answer these questions based on your project’s concerns and provide additional information and resources to make your static library or framework project go smoothly.

Know Your Supported Platforms

The first thing to know about is the difference between a Cocoa Touch Static Library (aka static library) and a Cocoa Touch Framework (aka framework). From a practical perspective, frameworks are only supported from iOS 8 onwards, whereas static libraries go “all the way back” to iOS 6, which is as far back as you can build an Xcode project using Xcode 7. If you need to support iOS versions before iOS 8, you should consider using a Cocoa Touch Static Library and writing your code in Objective-C.

Be Mindful of Swift Support

The next thing you should be aware of is that Cocoa Touch Static Libraries do not support Swift. So if you decide to use a Cocoa Touch Static Library, you need to use Objective-C. On that topic, Swift is supported back to iOS 7. If you need to support iOS 6 then Swift is definitely “off the table”. If you need to support iOS 7 and you want to use Swift, you will need to provide your source files to be included as raw files in the host app project. Otherwise if you only need to support iOS 8 and onwards, then you can create a Cocoa Touch Framework in Swift.

Plan Out Your Exporting

Platforms
The main thing to consider thus far is the base deployment target of apps that will be using your framework. If you are creating a framework for large scale distribution, you should be aware that many big publishers are still (at the time of this writing) supporting iOS 7 as a base deployment target. Generally the base deployment target is two versions below the latest one, so when iOS 10 is released (likely around 14-09-2016), we can expect the base to shift to iOS 8 for many publishers. At the time of writing this iOS 9 has 84% adoption, iOS 8 has 11%, and earlier versions of iOS comprise the remaining 5%.

Distribution
After you have built your framework, distribution will become your most important concern. Even though you have an Xcode project of type framework or static library, how do you provide your resource to others? Additionally, how do you provide instructions that are simple and easy to understand for the users of your product? If you are going to create a Cocoa Touch Framework, kodmunki has the best guide out there.

If you go with a Cocoa Touch Static Library instead, you should consider the Ray Wenderlich guide. Start with the section titled “Universal Frameworks”. Both of these are excellent guides that I have personally built frameworks from and these have been selected from all of the other pages on the Internet as the best sources have found to date.

In both of these approaches you will want to make sure that your Archive project target Build Settings has Build Active Architecture Only set to NO and Defines Module set to YES. Aside from that you should probably also define a User-Defined Build Setting of “BITCODE_GENERATION_MODE” with a value of “bitcode”, especially if you have bit code-related errors or warnings in your host app. It is not recommended “bitcode”, especially if you have bit code-related errors or warnings in your host app. It is not recommended that you disable bitcode generation in your host app in order to remove errors generated from your framework/static library product.

Prepare For Testing on Simulator

After you build and export your framework, it is important that you are able to include it in a host app for testing. You should be able to build and run on Simulator, physical device, and for “Generic iOS Device” without error. Beyond that you should also be certain that you can Archive your project with the framework included and export the app as well as submit to the App Store without error. I have seen failures occur at various stages in this process without previous error or warning and you should not consider your product complete until all of these boxes have been checked. Cocoa Touch Framework aka dynamic library Swift or Objective-C only supported on iOS 8 and later, fails during app submission if target <= iOS7 compiles to .framework Cocoa Touch Static Library aka static library only Objective-C (Swift is not supported) compiles to .lib supported “all the way down” to iOS 6.

Hopefully these resources will save you time and effort in your next iOS project!

Cocoa Touch Static Library vs. Cocoa Touch Framework

MVC Vs MVVM iOS

The MVC pattern splits an application up into three layers:

  • model layer
  • view layer
  • controller layer

Image

It’s clear to most developers what goes into the model and view layers of an application. But what is the task of the controller? The controller glues the model and view layers together, but I’m sure you agree that it does quite a bit more than that in most applications.

And, all too often, this leads to overweight controllers and the Massive View Controller syndrome. Not only is it difficult to maintain such controllers, it makes them incredibly hard to test and adding features can be a nightmare.

There Must Be a Better Solution

A little over a year ago, I was working on a project that involved a complex configuration view. It included a table view with many sections and a bunch of table view cells.

Table views are great. They are simple to use and quite flexible. But I’m sure you agree that they are tedious to use if the data you’re presenting isn’t uniform. Take the Settings application as an example. How would you implement this with table views and view controllers? Can you imagine the code you’d write to implement the root view controller? And what would the implementation of the tableView(_:cellForRowAt:) method look like?

I was facing a similar problem and I didn’t want to go the MVC route. Not this time. This was the first project I took MVVM seriously. There was a learning curve. I’m not going to lie. But the result was so beautiful and rewarding. I’m sure you know what I mean when I say the result was beautiful. We all know what beautiful code looks like. Right?

Not only was I able to keep the view controller lean and mean, I increased the testability and I could add and remove elements from the view controller with very little code and, more importantly, without being overwhelmed. Massive view controllers are often overwhelming, confusing, and … well … stressful. They can suck the lifeblood out of you. Right?

What Should/Shouldn’t a View Controller Do

Today, we take a closer look at what the controller is and isn’t in charge of. We also explore an alternative that doesn’t suffer from the same issues MVC suffers from. But let’s start by exploring each layer of the MVC pattern. This will give us a better idea of the problem MVC suffers from.

Model Layer

The model layer is in charge of the application’s business logic. It manages the state of the application. This also includes reading and writing data, persisting application state, and it may even include tasks related to data management, such as networking and data validation.

View Layer

The view layer has two important tasks:

  • presenting data to the user
  • handling user interaction

A core principle of the Model-View-Controller pattern is the view layer’s ignorance with respect to the model layer. Views are dumb objects. They only know how to present data to the user. They don’t know or understand what they are presenting.

Controller Layer

The view and model layers are glued together by one or several controllers. In iOS applications, that glue is a view controller, an instance of a UIViewController subclass. In macOS applications, controllers are most often instances of a NSWindowController subclass.

A controller knows about the view layer as well as the model layer. This usually results in tight coupling, making controllers the least reusable component of an MVC application. The view and model layers don’t know about the controller. The controller owns the views and the models it interacts with.

Massive View Controller Syndrome

If you’ve spent any amount of time reading books or tutorials about iOS or macOS development, then you’ve probably come across people complaining about MVC. I hope it is clear by now what that is. Right?

One of the key benefits of the Model-View-Controller pattern is a clear separation of concerns or responsibilities. It makes your life as a developer easier. Projects are easier to architect and structure. But that’s only part of the story. A lot of the code you write doesn’t belong in the view or model layer. No problem. Dump it in the controller. Problem solved. Hmm. We now know how that ends.

Data formatting is a common task. Imagine you’re developing an invoicing application. Each invoice has a creation date. Depending on the locale of the user, the date of an invoice needs to be formatted differently.

Image

The creation date of an invoice is stored in the model layer and the view displays the formatted date. That’s obvious. But who is responsible for formatting the date? The model? Maybe. The view? Remember that the view shouldn’t need to understand what it’s presenting to the user. But why should the model be responsible for a task that’s related to the user interface?

Wait a minute. What about our good old controller? Sure. Dump it in the controller. After thousands of lines of code, you end up with a bunch of massive view controllers, ready to burst and impossible to test. Isn’t the Model-View-Controller pattern the best thing ever?

Model-View-ViewModel to the Rescue

There are several alternative patterns that can help solve this problem. It introduces a fourth component or layer to the application architecture, the view model.

Image

The view model sits in between the model and controller layer. It’s the view model that owns the model, not the controller. Let me show you what happens when the view controller needs to display a piece data in the view it manages.

Image

The view controller asks its view model for data. The view model asks the model it manages for the raw value, a timestamp for example. It applies the necessary transformations to the raw value and returns a value the view controller can immediately display to the user in its view.

The view controller is no longer responsible for transforming the raw values of the model and it doesn’t even know about the model. That’s an important difference with the Model-View-Controller pattern.

MVC Vs MVVM iOS

iOS Architecture Patterns

Feeling weird while doing MVC in iOS? Have doubts about switching to MVVM? Heard about VIPER, but not sure if it worth it?

Keep reading, and you will find answers to questions above, if you don’t — feel free to complain in comments.

You are about to structure your knowledge about architectural patterns in iOS environment. We’ll briefly review some popular ones and compare them in theory and practice going over a few tiny examples. Follow links if you need more details about any particular one.

Mastering design patterns might be addictive, so beware: you might end up asking yourself more questions now than before reading this article, like these:

Who supposed to own networking request: a Model or a Controller?

How do I pass a Model into a View Model of a new View?

Who creates a new VIPER module: Router or Presenter?

Why care about choosing the architecture?

Because if you don’t, one day, debugging a huge class with dozens different things, you’ll find yourself being unable to find and fix any bugs in your class.”. Naturally, it is hard to keep this class in mind as whole entity, thus, you’ll always be missing some important details. If you are already in this situation with your application, it is very likely that:

  • This class is the UIViewController subclass.
  • Your data stored directly in the UIViewController
  • Your UIViews do almost nothing
  • The Model is a dumb data structure
  • Your Unit Tests cover nothing

And this can happen, even despite the fact that you are following Apple’s guidelines and implementing Apple’s MVC pattern, so don’t feel bad. There is something wrong with the Apple’s MVC, but we’ll get back to it later.

Let’s define features of a good architecture:

  1. Balanced distribution of responsibilities among entities with strict roles.
  2. Testability usually comes from the first feature (and don’t worry: it is easy with appropriate architecture).
  3. Ease of use and a low maintenance cost.

Why Distribution?

Distribution keeps a fair load on our brain while we trying to figure out how things work. If you think the more you develop the better your brain will adapt to understanding complexity, then you are right. But this ability doesn’t scale linearly and reaches the cap very quickly. So the easiest way to defeat complexity is to divide responsibilities among multiple entities following the single responsibility principle.

Why Testability?

This is usually not a question for those who already felt gratitude to unit tests, which failed after adding new features or due to refactoring some intricacies of the class. This means the tests saved those developers from finding issues in runtime, which might happen when an app is on a user’s device and the fix takes a week to reach the user.

Why Ease of use?

This does not require an answer but it is worth mentioning that the best code is the code that has never been written. Therefore the less code you have, the less bugs you have. This means that desire to write less code should never be explained solely by laziness of a developer, and you should not favour a smarter solution closing your eyes to its maintenance cost.


MV(X) essentials

Nowadays we have many options when it comes to architecture design patterns:

First three of them assume putting the entities of the app into one of 3 categories:

  • Models — responsible for the domain data or a data access layer which manipulates the data, think of ‘Person’ or ‘PersonDataProvider’ classes.
  • Views — responsible for the presentation layer (GUI), for iOS environment think of everything starting with ‘UI’ prefix.
  • Controller/Presenter/ViewModel — the glue or the mediator between the Model and the View, in general responsible for altering the Model by reacting to the user’s actions performed on the View and updating the View with changes from the Model.

Having entities divided allows us to:

  • understand them better (as we already know)
  • reuse them (mostly applicable to the View and the Model)
  • test them independently

Let’s start with MV(X) patterns and get back to VIPER later.

MVC

How it used to be

Before discussing Apple’s vision of MVC let’s have a look on the traditional one.

Traditional MVC

In this case, the View is stateless. It is simply rendered by the Controller once the Model is changed. Think of the web page completely reloaded once you press on the link to navigate somewhere else. Although it is possible to implement the traditional MVC in iOS application, it doesn’t make much sense due to the architectural problem — all three entities are tightly coupled, each entity knows about the other two. This dramatically reduces reusability of each of them — that is not what you want to have in your application. For this reason, we skip even trying to write a canonical MVC example.

Traditional MVC doesn’t seems to be applicable to modern iOS development.

Apple’s MVC

Expectation

Cocoa MVC

The Controller is a mediator between the View and the Model so that they don’t know about each other. The least reusable is the Controller and this is usually fine for us, since we must have a place for all that tricky business logic that doesn’t fit into the Model.

In theory, it looks very straightforward, but you feel that something is wrong, right? You even heard people unabbreviating MVC as the Massive View Controller. Moreover, view controller offloading became an important topic for the iOS developers. Why does this happen if Apple just took the traditional MVC and improved it a bit?

Apple’s MVC

Reality

Realistic Cocoa MVC

Cocoa MVC encourages you to write Massive View Controllers, because they are so involved in View’s life cycle that it’s hard to say they are separate. Although you still have ability to offload some of the business logic and data transformation to the Model, you don’t have much choice when it comes to offloading work to the View, at most of times all the responsibility of the View is to send actions to the Controller. The view controller ends up being a delegate and a data source of everything, and is usually responsible for dispatching and cancelling the network requests and… you name it.

How many times have you seen code like this:

var userCell = tableView.dequeueReusableCellWithIdentifier(identifier) as UserCell
 userCell.configureWithUser(user)

The cell, which is the View configured directly with the Model, so MVC guidelines are violated, but this happens all the time, and usually people don’t feel it is wrong. If you strictly follow the MVC, then you supposed to configure the cell from the controller, and don’t pass the Model into the View, and this will increase the size of your Controller even more.

Cocoa MVC is reasonably unabbreviated as the Massive View Controller.

The problem might not be evident until it comes to the Unit Testing(hopefully, it does in your project). Since your view controller is tightly coupled with the view, it becomes difficult to test because you have to be very creative in mocking views and their life cycle, while writing the view controller’s code in such a way, that your business logic is separated as much as possible from the view layout code.

Let’s have a look on the simple playground example:

 import UIKit

 

struct Person { // Model
let firstName: String
let lastName: String
}
class GreetingViewController : UIViewController { // View + Controller
var person: Person!
let showGreetingButton = UIButton()
let greetingLabel = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
self.showGreetingButton.addTarget(self, action: didTapButton:, forControlEvents: .TouchUpInside)
}
func didTapButton(button: UIButton) {
let greeting = Hello + + self.person.firstName + + self.person.lastName
self.greetingLabel.text = greeting
}
// layout code goes here
}
// Assembling of MVC
let model = Person(firstName: David, lastName: Blaine)
let view = GreetingViewController()
view.person = model;
MVC example

MVC assembling can be performed in the presenting view controller

This doesn’t seem very testable, right? We can move generation of greeting into the new GreetingModel class and test it separately, but we can’t test any presentation logic (although there is not much of such logic in the example above) inside the GreetingViewController without calling the UIView related methods directly (viewDidLoad, didTapButton) which might cause loading all views, and this is bad for the unit testing.

In fact, loading and testing UIViews on one simulator (e.g. iPhone 4S) doesn’t guarantee that it would work fine on the other devices (e.g. iPad), so I’d recommend to remove “Host Application” from your Unit Test target configuration and run your tests without your application running on simulator.

The interactions between the View and the Controller aren’t really testable with Unit Tests

With all that said, it might seems that Cocoa MVC is a pretty bad pattern to choose. But let’s assess it in terms of features defined in the beginning of the article:

  • Distribution the View and the Model in fact separated, but the View and the Controller are tightly coupled.
  • Testability — due to the bad distribution you’ll probably only test your Model.
  • Ease of use — the least amount of code among others patterns. In addition everyone is familiar with it, thus, it’s easily maintained even by the unexperienced developers.

Cocoa MVC is the pattern of your choice if you are not ready to invest more time in your architecture, and you feel that something with higher maintenance cost is an overkill for your tiny pet project.

Cocoa MVC is the best architectural pattern in terms of the speed of the development.

MVP

Cocoa MVC’s promises delivered

Passive View variant of MVP

Doesn’t it look exactly like the Apple’s MVC? Yes, it does, and it’s name is MVP (Passive View variant). But wait a minute… Does this mean that Apple’s MVC is in fact a MVP? No, its not, because if you recall, there, the View is tightly coupled with the Controller, while the MVP’s mediator, Presenter, has nothing to do with the life cycle of the view controller, and the View can be mocked easily, so there is no layout code in the Presenter at all, but it is responsible for updating the View with data and state.

What if I told you, the UIViewController is the View.

In terms of the MVP, the UIViewController subclasses are in fact the Views and not the Presenters. This distinction provides superb testability, which comes at cost of the development speed, because you have to make manual data and event binding, as you can see from the example:

 import UIKit

 

struct Person { // Model
let firstName: String
let lastName: String
}
protocol GreetingView: class {
func setGreeting(greeting: String)
}
protocol GreetingViewPresenter {
init(view: GreetingView, person: Person)
func showGreeting()
}
class GreetingPresenter : GreetingViewPresenter {
unowned let view: GreetingView
let person: Person
required init(view: GreetingView, person: Person) {
self.view = view
self.person = person
}
func showGreeting() {
let greeting = Hello + + self.person.firstName + + self.person.lastName
self.view.setGreeting(greeting)
}
}
class GreetingViewController : UIViewController, GreetingView {
var presenter: GreetingViewPresenter!
let showGreetingButton = UIButton()
let greetingLabel = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
self.showGreetingButton.addTarget(self, action: didTapButton:, forControlEvents: .TouchUpInside)
}
func didTapButton(button: UIButton) {
self.presenter.showGreeting()
}
func setGreeting(greeting: String) {
self.greetingLabel.text = greeting
}
// layout code goes here
}
// Assembling of MVP
let model = Person(firstName: David, lastName: Blaine)
let view = GreetingViewController()
let presenter = GreetingPresenter(view: view, person: model)
view.presenter = presenter
MVP example

Important note regarding assembly

The MVP is the first pattern that reveals the assembly problem which happens due to having three actually separate layers. Since we don’t want the View to know about the Model, it is not right to perform assembly in presenting view controller (which is the View), thus we have to do it somewhere else. For example, we can make the app-wide Router service which will be responsible for performing assembly and the View-to-View presentation. This issue arises and has to be addressed not only in the MVP but also in all the following patterns.

Let’s look on the features of the MVP:

  • Distribution — we have the most of responsibilities divided between the Presenter and the Model, with the pretty dumb View (in the example above the Model is dumb as well).
  • Testability — is excellent, we can test most of the business logic due to the dumb View.
  • Easy of use — in our unrealistically simple example, the amount of code is doubled compared to the MVC, but at the same time, idea of the MVP is very clear.

MVP in iOS means superb testability and a lot of code.

MVP

With Bindings and Hooters

There is the other flavour of the MVP — the Supervising Controller MVP. This variant includes direct binding of the View and the Model while the Presenter (The Supervising Controller) still handles actions from the View and is capable of changing the View.

Supervising Presenter variant of the MVP

But as we have already learned before, vague responsibility separation is bad, as well as tight coupling of the View and the Model. That is similar to how things work in Cocoa desktop development.

Same as with the traditional MVC, I don’t see a point in writing an example for the flawed architecture.

MVVM

The latest and the greatest of the MV(X) kind

The MVVM is the newest of MV(X) kind thus, let’s hope it emerged taking into account problems MV(X) was facing previously.

In theory the Model-View-ViewModel looks very good. The View and the Model are already familiar to us, but also the Mediator, represented as the View Model.

MVVM

It is pretty similar to the MVP:

  • the MVVM treats the view controller as the View
  • There is no tight coupling between the View and the Model

In addition, it does binding like the Supervising version of the MVP; however, this time not between the View and the Model, but between the View and the View Model.

So what is the View Model in the iOS reality? It is basically UIKit independent representation of your View and its state. The View Model invokes changes in the Model and updates itself with the updated Model, and since we have a binding between the View and the View Model, the first is updated accordingly.

Bindings

I briefly mentioned them in the MVP part, but let’s discuss them a bit here. Bindings come out of box for the OS X development, but we don’t have them in the iOS toolbox. Of course we have the KVO and notifications, but they aren’t as convenient as bindings.

So, provided we don’t want to write them ourselves, we have two options:

In fact, nowadays, if you hear “MVVM” — you think ReactiveCocoa, and vice versa. Although it is possible to build the MVVM with the simple bindings, ReactiveCocoa (or siblings) will allow you to get most of the MVVM.

There is one bitter truth about reactive frameworks: the great power comes with the great responsibility. It’s really easy to mess up things when you go reactive. In other words, if do something wrong, you might spend a lot of time debugging the app, so just take a look at this call stack.

Reactive Debugging

In our simple example, the FRF framework or even the KVO is an overkill, instead we’ll explicitly ask the View Model to update using showGreeting method and use the simple property for greetingDidChange callback function.

 import UIKit

 

struct Person { // Model
let firstName: String
let lastName: String
}
protocol GreetingViewModelProtocol: class {
var greeting: String? { get }
var greetingDidChange: ((GreetingViewModelProtocol) -> ())? { get set } // function to call when greeting did change
init(person: Person)
func showGreeting()
}
class GreetingViewModel : GreetingViewModelProtocol {
let person: Person
var greeting: String? {
didSet {
self.greetingDidChange?(self)
}
}
var greetingDidChange: ((GreetingViewModelProtocol) -> ())?
required init(person: Person) {
self.person = person
}
func showGreeting() {
self.greeting = Hello + + self.person.firstName + + self.person.lastName
}
}
class GreetingViewController : UIViewController {
var viewModel: GreetingViewModelProtocol! {
didSet {
self.viewModel.greetingDidChange = { [unowned self] viewModel in
self.greetingLabel.text = viewModel.greeting
}
}
}
let showGreetingButton = UIButton()
let greetingLabel = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
self.showGreetingButton.addTarget(self.viewModel, action: showGreeting, forControlEvents: .TouchUpInside)
}
// layout code goes here
}
// Assembling of MVVM
let model = Person(firstName: David, lastName: Blaine)
let viewModel = GreetingViewModel(person: model)
let view = GreetingViewController()
view.viewModel = viewModel
MVVM example

And again back to our feature assessment:

  • Distribution — it is not clear in our tiny example, but, in fact, the MVVM’s View has more responsibilities than the MVP’s View. Because the first one updates it’s state from the View Model by setting up bindings, when the second one just forwards all events to the Presenter and doesn’t update itself.
  • Testability — the View Model knows nothing about the View, this allows us to test it easily. The View might be also tested, but since it is UIKit dependant you might want to skip it.
  • Easy of use — its has the same amount of code as the MVP in our example, but in the real app where you’d have to forward all events from the View to the Presenter and to update the View manually, MVVM would be much skinnier if you used bindings.

The MVVM is very attractive, since it combines benefits of the aforementioned approaches, and, in addition, it doesn’t require extra code for the View updates due to the bindings on the View side. Nevertheless, testability is still on a good level.


VIPER

LEGO building experience transferred into the iOS app design

VIPER is our last candidate, which is particularly interesting because it doesn’t come from the MV(X) category.

By now, you must agree that the granularity in responsibilities is very good. VIPER makes another iteration on the idea of separating responsibilities, and this time we have five layers.

VIPER
  • Interactor — contains business logic related to the data (Entities) or networking, like creating new instances of entities or fetching them from the server. For those purposes you’ll use some Services and Managers which are not considered as a part of VIPER module but rather an external dependency.
  • Presenter — contains the UI related (but UIKit independent) business logic, invokes methods on the Interactor.
  • Entities — your plain data objects, not the data access layer, because that is a responsibility of the Interactor.
  • Router — responsible for the segues between the VIPER modules.

Basically, VIPER module can be a one screen or the whole user story of your application — think of authentication, which can be one screen or several related ones. How small are your “LEGO” blocks supposed to be? — It’s up to you.

If we compare it with the MV(X) kind, we’ll see a few differences of the distribution of responsibilities:

  • Model (data interaction) logic shifted into the Interactor with the Entities as dumb data structures.
  • Only the UI representation duties of the Controller/Presenter/ViewModel moved into the Presenter, but not the data altering capabilities.
  • VIPER is the first pattern which explicitly addresses navigation responsibility, which is supposed to be resolved by the Router.

Proper way of doing routing is a challenge for the iOS applications, the MV(X) patterns simply don’t address this issue.

The example doesn’t cover routing or interaction between modules, as those topics are not covered by the MV(X) patterns at all.

 import UIKit

 

struct Person { // Entity (usually more complex e.g. NSManagedObject)
let firstName: String
let lastName: String
}
struct GreetingData { // Transport data structure (not Entity)
let greeting: String
let subject: String
}
protocol GreetingProvider {
func provideGreetingData()
}
protocol GreetingOutput: class {
func receiveGreetingData(greetingData: GreetingData)
}
class GreetingInteractor : GreetingProvider {
weak var output: GreetingOutput!
func provideGreetingData() {
let person = Person(firstName: David, lastName: Blaine) // usually comes from data access layer
let subject = person.firstName + + person.lastName
let greeting = GreetingData(greeting: Hello, subject: subject)
self.output.receiveGreetingData(greeting)
}
}
protocol GreetingViewEventHandler {
func didTapShowGreetingButton()
}
protocol GreetingView: class {
func setGreeting(greeting: String)
}
class GreetingPresenter : GreetingOutput, GreetingViewEventHandler {
weak var view: GreetingView!
var greetingProvider: GreetingProvider!
func didTapShowGreetingButton() {
self.greetingProvider.provideGreetingData()
}
func receiveGreetingData(greetingData: GreetingData) {
let greeting = greetingData.greeting + + greetingData.subject
self.view.setGreeting(greeting)
}
}
class GreetingViewController : UIViewController, GreetingView {
var eventHandler: GreetingViewEventHandler!
let showGreetingButton = UIButton()
let greetingLabel = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
self.showGreetingButton.addTarget(self, action: didTapButton:, forControlEvents: .TouchUpInside)
}
func didTapButton(button: UIButton) {
self.eventHandler.didTapShowGreetingButton()
}
func setGreeting(greeting: String) {
self.greetingLabel.text = greeting
}
// layout code goes here
}
// Assembling of VIPER module, without Router
let view = GreetingViewController()
let presenter = GreetingPresenter()
let interactor = GreetingInteractor()
view.eventHandler = presenter
presenter.view = view
presenter.greetingProvider = interactor
interactor.output = presenter

Yet again, back to the features:

  • Distribution — undoubtedly, VIPER is a champion in distribution of responsibilities.
  • Testability —no surprises here, better distribution — better testability.
  • Easy of use — finally, two above come in cost of maintainability as you already guessed. You have to write huge amount of interface for classes with very small responsibilities.

So what about LEGO?

While using VIPER, you might feel like building The Empire State Building from LEGO blocks, and that is a signal that you have a problem. Maybe, it’s too early to adopt VIPER for your application and you should consider something simpler. Some people ignore this and continue shooting out of cannon into sparrows. I assume they believe that their apps will benefit from VIPER at least in the future, even if now the maintenance cost is unreasonably high. If you believe the same, then I’d recommend you to try Generamba — a tool for generating VIPER skeletons. Although for me personally it feels like using an automated targeting system for cannon instead of simply taking a sling shot.

Conclusion

We went though several architectural patterns, and I hope you have found some answers to what bothered you, but I have no doubt that you realised that there is no silver bullet so choosing architecture pattern is a matter of weighting tradeoffs in your particular situation.

Therefore, it is natural to have a mix of architectures in same app. For example: you’ve started with MVC, then you realised that one particular screen became too hard to maintain efficiently with the MVC and switched to the MVVM, but only for this particular screen. There is no need to refactor other screens for which the MVC actually does work fine, because both of architectures are easily compatible.

iOS Architecture Patterns