The fundamental software architecture pattern in iOS and Mac OS development is the Model-View-Controller pattern (MVC). The idea of this pattern is, that each of these three layers has a clear and precise role, which leads to more reusable code and less bugs. However, in iOS development there is a drastic tendency that the controller layer does more than it should do. In this post we discuss some ways of avoiding this trap.
Model-View-Controller: The Theory
Let’s take a look at the three layers of the MVC pattern:
- The model layer holds all the data and has all the logic that deals with the data – the so-called business logic. However, the model knows nothing about the presentation of this data. That means that the model layer could be used without any changes in both an iOS and MacOS X application. The model is allowed to speak with the controller layer. However, this happens either about notifications or about protocols that some view controllers implement. But the model layer is not allowed to speak in any way with the view layer!
- The view layer has all objects that the user can see. This will be almost always UIViews or subclasses of UIView. Similar to the model layer, the view layer is allowed to speak to the view controller but not to the model layer!
- The main responsibility of the controller layer is the communication between model layer and view layer. Therefore, it is allowed to speak to both model layer and view layer.
If these principles are respected, your application will be well structured and highly reusable.
Model-View-Controller: The Reality
Unfortunately, reality looks a little bit different. There is the tendency to put too much code into the controller layer. For example, if your are programming a calculator it is of course possible to put all the calculator logic in the controller layer! On the first sight, this is the obvious approach. If your are new to the MVC pattern, it feels more natural this way. But in the end, it is not a good solution. As already said before, in the calculator example you would have a big problem porting the application to another platform. It will also lead to redundant code because main logic features need to the coded several times, if they are not easily accessible.
On the other hand, if you have a good software architecture, that lives and breathes the MVC pattern, then you will have much more classes in your project. This has sometimes a deterrent effect to some people, but if you have a good structure of your project file, then this is not a big issue at all.
There is not an all-embracing solution for avoiding the MVC-trap. But there are many small things you can do. And in the end these solutions add up and your app’s architecture will become much better:
Solution #1: Planning
One of the main reasons for a bad MVC architecture is an insufficient planing of the project. Before you start to create a Xcode project, you should have an idea about the architecture of your application. Most people don’t like it, but it is very advisable to create an UML class diagram. Of course it will change a lot during the project, but it helps to get an approximate idea of the app’s architecture.
Solution #2: Outsource your delegates
Delegates are a very important element in a good software architecture, because the usage of delegates leads to less inheritance and less coupling. However, it leads also to a lot of code, if a view controller confirms to several delegates like UITableViewControllerDelegate, UIScrollViewDelegate, UIAlertViewDelegate etc. So one important step is to actually outsource these delegates in separate objects on its own. This will lead to a much better code structure, even if these objects live in the same layer. There is a previous post about this topic with focus on UITableViewDataSource.
Solution #3: Create logic objects
This is a very important point. Create logic objects!!! For example, if you are programming a calculator, you should create a separate object called CalculatorLogic. This object does all the stuff related to the actual calculating. The view controller just hands the input to this logic object. Then, this object informs the controller layer about new results, which then informs the view layer about the new visualization information.
Solution #4: Create helper objects
This is similar to the point before. There are some task that are not pure business logic, but still belong to the model layer. These tasks act in a more supporting way. For example, this could be the network communication with a backend service. These network calls should not be placed in a view controller directly! Instead, a helper object can have a function called getAllProducts and the view controller calls this function. This has the big advantage that you have one function for a specific task. And this function can also be called from other view controllers as well. If you decide one day to change the network logic, you have one central point for this.
Another good example for a helper object is a database connection.
Solution #5: Think about your code
Like in many other areas, the first shot is rarely perfect. So if you have completed a task, do not go immediately over to the next task, but instead think about your code! Often you will see something, which could be done better. For example, this could be the creation of a helper object. This mini-refactoring step takes some time, but it will increase the quality of your code dramatically.
Solution #6: Look outside the box
Like the last one, this is a more general point. Over the time developers create an individual style of programming. On the one hand this is good, but on the other hand it can hold you back from becoming a better developer. So take a look outside the box and look at other people’s code and don’t hesitate to break new ground. If you have alway an open mind, it is much easier to improve both your skills and the software architecture of your projects.
In this blog post we have discussed the problem of a big controller layer. Although there is not an all-embracing solution for this problem, you can do several things that add up to a much better software architecture.
Image: @ Marco Uliana / Shutterstock.com