Update Note : Felipe Laso-Marsetti updated this tutorial for Swift 4.2, Xcode 10 and iOS 12. Rui Peres wrote the original.
As a new iOS developer, there is a lot of information you need to master: a new language, new frames and APIs, and Apple's recommended architectural pattern Model View Controller ] or MVC too short.
The MVC pattern is common in iOS development. Though it is not a difficult pattern to understand and get to know, there are things to consider to avoid common pitfalls.
Getting up to speed with iOS development can be a daunting task, and most often MVC does not get as much attention as APIs or programming languages. This can cause major architectural problems in your apps down the road.
This tutorial helps you avoid common mistakes that lead to apps that are too difficult to expand. You learn a good approach to what (and not) doing as you use MVC to build your app using best practices, learned over the years of iOS development.
In this tutorial you will not do any coding. Instead, you will go through a project that uses MVC with best practice in mind.
Use Download Materials button at the top or bottom of this tutorial to download the trial project.
What is MVC
With the project handy, it's time to start learning about the model, display and controls. But first, what is MVC really?
Note : If you already know the MVC concept, you are welcome to skip to the next section, where you begin to join best practices.
MVC is a software development pattern consisting of three main objects:
- Model is where your data is located. Things like endurance, model objects, parsers, managers, and network code live there.
- The team View is the face of your app. Its classes are often reusable because they do not contain any domain specific logic. For example, a
UILabelis a display that presents text on the screen and is reusable and expandable.
- The controller controls between the display and the model via the delegation pattern. In an ideal scenario, the controller will not know specifically the prospect it has to do with. Instead, it will communicate with an abstraction via a protocol. A classic example is how a
UITableViewcommunicates with its data source via the protocol
When you put everything together, it looks like this:
Each of these objects is meant to be separated from the other, and each fulfills a particular role. When you build an app that uses a particular pattern, in this case MVC, the goal is to stick to the pattern when you build all the layers on your app.
Apple's MVC documentation explains these layers in detail and can give you a good theoretical understanding. From a practical perspective, however, it falls a little short.
In this tutorial you learn to treat MVC as a pattern and not as a strict rule that you must never break. As is the case with many things in software development, nothing is perfect, nor is it MVC. There are gray areas that you enter, but no decision you make is the wrong decision. As long as you don't have files that are too big or code that is difficult to expand on, you'll probably do a good job. Use MVC – and other patterns for that matter – as architectural guidelines and basis for your app.
Having said that, it is time to look at each layer in more detail.
The model layer includes the app's data. No surprise there, but there are usually other classes and objects in the projects you can include in this layer:
- Network Code : You just use a single class of network communication over your entire app. It makes it easy to abstract concepts that are common to all network requests such as HTTP headers, responses, and error handling, and more.
- Persistence code : You use this when you persist in a database, Core Data or store data on a device.
- Parsing code : You should include objects that analyze network responses in the model layer. For example, in Swift model objects, you can use JSON encoding / decoding to handle parsing. In this way, everything is independent, and your network layer does not need to know the details of all your model objects to analyze them. Business and analysis analysis is completely independent within the models.
- Leaders and Abstraction Law / Classes : Everyone uses them, everyone needs them, no one knows what to call or where they belong. It is normal to have the typical "manager" objects that often act as glue between other classes. These can also be wrappers around the lower level, more robust API: a keychain wrapper on iOS, a class to help with alerts or a model that helps you work with HealthKit.
- Data Sources and Delegates : Something that may be less common is developers dependent on model objects such as data source or delegate of other components such as table or collection views. It is common to see these implemented in the control layer even when there is a lot of custom logic that is best preserved in the room.
- Constants : It is good practice to have a file with constants. Consider putting these into a structure of structures or variables. In this way, you can restore the names of signboards, date formats, colors, etc.
- Helpers and Extensions : In your projects you will often add methods to expand the possibilities of strings, collections, etc. These can also be considered as part of the model.
There are several classes and objects you can include, but these seem to be the most common. Again, the goal is not to focus too much on the semantics of what is or is not a model. It is rather to have a solid foundation for getting your work done.
From a test perspective, the model is an excellent candidate. You can verify business logic, mock some of the networks or endurance methods, or add tests around sensitive parts of your model layer.
When users communicate with your app, they interact with the display layer. It should not contain any business logic. In code skills you usually see:
UIViewsubcategories: These range from a basic
UIViewto complex custom user interfaces.
- Classes that are part of UIKit / AppKit.
- Core Animation.
- Nuclear graphics.
Typical code smells found in this layer manifest in different ways, but boils down to include everything that is not related to the user interface of your display layer. This can include network calls, business logic, manipulate models, and so on.
Use the following as a checklist when inspecting your display layer:
- Does it work with the model layer?
- Does it have any business logic
- Are you trying to do everything that is not related to the user interface?
If you answer "yes" to any of these questions, you have the opportunity to clean up and refactor.
Of course, these rules are & # 39; Not written in stone, and sometimes you have to bend them. Nevertheless, it is important to keep them in mind.
Good writing components are often reusable, but do not focus on it from the beginning. It's easy to get caught up in the idea of taking a cool button you built and make it compatible for a dozen different scenarios that your app might not need.
Consider making components reusable only when you actually need it. When you have multiple usage cases, it's time to make a component more generic.
From a testing perspective, UI testing in IOS can test things like transitions, UI elements with specific attributes, or UI interactions that work as intended.
The control layer is the least reusable part of your app as it often involves your domain specific rules. It should not be surprising that what makes sense in your app will not always make sense to anyone else. The controller will then use all the elements of your model layer to define the flow of information in your app.
Usually, you see classes from this team determining things like:
- What should I first access: the persistence
- How often should I update the app?
- What should the next screen be and under what circumstances?
- If the app goes to the background, what should I clean up?
- The user dropped onto a cell; what should i do next?
Think of the control layer as the brain or engine of the app; It determines what happens next.
You probably won't do much testing in the control layer, mostly it is meant to kick things, trigger data loads, handle UI interactions, communicate between user interface and model, etc.
Put it all
Now that you have a better understanding of the teams involved in the MVC pattern, it is time to see it in action with this training example app.
Open the training example and run the app. This app is a WWDC-like app that shows sessions and participants for the event. The app loads data from JSON files into the app package at launch. Loading data triggers the controls to update the view and start waiting for user interaction.
To start, expand the folder Model . The three "pure" model classes are
Session . Notice how these correspond to
Decodable so analysis from a JSON response is easy.
From there you have other model files that are part of your network calls. This tutorial project loads a file from the app's bundle, but you can add a remote URL to load a file or call a web service. The main classes are:
Network : A cover around
- NetworkError : To handle various errors during the request / response process
- WebService : To add a help method to load both participants and sessions
In the note is Network .swift which has a method that uses generics to request JSON from a URL and parse it into an object type you specify in the method call. It handles HTTP responses and codes, errors, parsing, concatenation and making
URLSession call for you.
These files are small, simple, contain their own logic and you can test them with maximum, some mock methods.
Continue with the view, it is mostly seen in your storyboard files. This is good as it is not only more visual but reduces the code lines you write mean reducing the amount of possible errors you can introduce.
You can also have display logic in files, as is the case with SessionCell.swift especially when making custom animations or user interface elements. Your views should not know about business logic, interact with or know about model objects or do anything that is not related to the view itself.
Testing components of the display layer, from a purely unit test perspective, is not as simple or useful, especially when dealing with XIB or storyboards. This is because programmatic creation of impressions or controls will not trigger all methods in the display life or set up non-programmatic constraints. You can do UI tests and make sure your tests also cover the display layer.
Finally, you come to the control team, which is where things become interesting, as they act as glue between display and model.
eighteenth view controller and
SessionViewController have the same concept. These show a list of items that you can choose to view details. When presenting the details of a selected object, use
Some things to note are:
AppDelegateis responsible for loading event data and then submitting it to each of the controls.
- When the controller receives data, it triggers a reloading of the data table.
- The controls act as data source and delegate of the table view.
- The Controls process passes the information when the user selects a session or event.
It's all very thin, clean and easy to understand. You can even, for more robust projects, create separate classes or objects to act as data sources or delegates, and simplify your boards.
There is no heavy reliance on completion blocks, delegation (beyond what the table view needs) or mixes business logic into impressions or controls. You also don't have the dreaded "MVC: Massive View Controllers." This happens when too much of your business logic lives inside the controller.
Some tips to help you notice when an item in a team can exceed the limits are:
- The controller makes network requests, parsing, or persistence.
- The controller (or any file) has hundreds or thousands
- Views accept model objects to "configure" themselves or set up UI items for display.
- Controllers do a lot of business logic, calculations, data resolution or manipulation.
Where To Go From Here?
MVC is a pattern, a guide for you to your architect app; It is not a strict set of rules you must adhere to.
As with everything that is meant to serve as a guide, you may disagree with some of the content or implementations of this tutorial. You can do things differently or adjust it to suit your needs. It is okay. There are many ways to work with this dough as we call the model display controller pattern.
TL; DR is: If you have found changes or tweaks that work for you, your team, your business or your workflow, go for it. As long as your app is flexible and able to grow, you're good to go.
No architecture, old or new, is a silver bullet and you should always focus on good technical principles first.
If you have comments or questions, please join the forum discussion below! I hope you have had this tutorial and learned a little more about the MVC pattern.