Understanding Model-View-Controller (MVC) In Swift

Written by Reinder de Vries on July 12 2017 in App Development

Understanding Model-View-Controller (MVC) In Swift

Model-View-Controller (MVC) is an exceptionally powerful software architectural pattern for creating apps. MVC is the answer to the question: “How should I organize code in my iOS app?”

You already know Object-Oriented Programming (OOP). OOP organizes your Swift code in classes that have properties and functions, much like bob is an instance of class Human, that has properties legs and noseSize.

Model-View-Controller builds on top of Object-Oriented Programming. It structures the flow of data and interaction in your app. When you’re asking yourself: “How should I pass data from one part of my app to another?” then Model-View-Controller is a smart answer.

When it comes to architectural patterns and apps, you can choose from a great number of designs: Model-View-ViewModel (MVVM), Reactive Programming (RP) and Model-View-Whatever (MVW). Next to that, you can also use a number of smaller software design patterns, like Delegation and Extension.

In this article, you’ll learn how to use Model-View-Controller (MVC) to better structure your app and its data. Many of the Apple frameworks use MVC, so it pays dividends to understand this architectural pattern and apply it to your iOS development.

Ready? Let’s go.

  1. What’s Model-View-Controller (MVC)?
  2. Why You Should Use MVC
  3. Practical Uses in iOS Development
  4. Further Reading

What’s Model-View-Controller (MVC)?

Let’s get started with messaging. No, not sending chat messages – but sending messages from one part of your app to the other.

A “message” in iOS development is simply the name of a method, and any parameters associated with it, that you send to an instance of an object.

Like this:


You’re sending the sit() message to dog. Why don’t you just call those “functions” and “objects”? Well, a function and an object are static – they don’t have intent. You want to be clear about what calling a function implies: sending a message!

If you think about messages, and sending and receiving them, you’re automatically thinking about sending and receiving data. In iOS development, messages are often much more complex than dog.sit(). Check out this example:

rook.move(steps: 10, direction: .forward)
rook.move(steps: 3, direction: .right)

In the above example, you’re sending messages to the chess piece rook. You tell it to move 10 steps forward, and 3 steps to the right. With messaging you’re instructing it to move, sending different pieces of data to the chess piece.

Enough about messaging. Let’s get into Model-View-Controller…

MVC, short for Model-View-Controller, is an software architectural pattern. You use it to create the architecture for your app, kind of how an architect designs a building before a builder constructs it.

The Model-View-Controller concept describes 3 components:

  • Model, a wrapper of data
  • View, a representation of a user interface (UI)
  • Controller, an intermediary between the Model and the View

Model View Controller

You use these 3 components together to structure your app. Every component has a distinct role:

  • The Model encapsulates a particular set of data, and contains logic to manipulate that data. When you think about accounting software, an Invoice is a model. When you think of a Twitter app, a Tweet is a model.
  • The View is an object that the user can see, in a user interface (UI). In the accounting software, a UILabel that displays the invoice address is a view. In a Twitter app, the TweetView is a view that displays a tweet.
  • The Controller controls all logic that goes between the View and the Model. It transports messages between the View and the Model, and vice versa.

In iOS development, and the UIKit framework in particular, you’ve probably already worked with a ton of Models, Views and Controllers without knowing it.

Some examples:

  • Objects like UIButton, UIView and UILabel are all examples of Views. More complex views like MKMapView contain many visual properties like mapType and isZoomEnabled.
  • Objects like UIViewController, CLLocationManager and UINavigationController are examples of Controllers. In iOS you also use delegates, a special kind of controller that you can hand-off messages to.
  • When using the Core Data SDK, your .xcdatamodeld file contains your app’s Models. In Realm, these models are created as simple classes. In Firebase and Parse Servers these models are represented as JSON objects.

The final piece of the Model-View-Controller puzzle is the flow of data. You can see that in the image above.

Apart from the 3 Model-View-Controller components, you can see how the messages can flow from one component to the other.

This happens in 4 ways:

  • The View tells the Controller when a user interaction takes place
  • The Controller updates the View when the data changes
  • The Controller updates the Model when the data changes
  • The Model notifies the Controller when data changes

You can see 2 kinds of flow in the above diagram:

  • The top flow from View → Controller → Model happens when a user interaction in the View causes the data in the Model to change
  • The bottom flow from Model → Controller → View happens when the data in the Model changes and the View needs to update accordingly

Let’s talk about a quick scenario for Model-View-Controller: a to-do app.

Imagine that the to-do app has a number of Views in a list, one for every task. Every View is backed by a Model that has the data for that task, like title and isCompleted.

Now, the following happens:

  • The user taps on a task View, and this causes the iPhone on-screen keyboard to pop up – the task title can now be edited
  • The user edits the task title, like changing it to "Get groceries", and taps the Submit button
  • The Controller now responds to the data change and updates the Model accordingly

Likewise, this can happen too:

  • The Model data for a task changes, because of data that comes in from a cloud back-end like Firebase
  • The Model then updates the Controller, sending a message that its data has changed
  • The Controller will then propagate that message and update the View accordingly

That’s it! That’s all there is to it. Let’s now figure out how to put this theory into practice…

Learn how to build iOS apps

Get started with iOS 13 and Swift 5

Sign up for my iOS development course, and learn how to build great iOS 13 apps with Swift 5 and Xcode 11.

Why You Should Use MVC

Model-View-Controller is a fundamental concept to understand, especially in iOS development. Many iOS frameworks, like UIKit, use the MVC pattern to structure data flow and messaging.

One of your jobs as an app developer is to keep your apps maintainable. This means that you should document your code, keep your code concise and readable, and adhere to a strict structure.

Model-View-Controller is that stucture. It keeps your code from becoming one big pile of chaos. That’s the first and foremost benefit of using Model-View-Controller. Don’t write spaghetti code!

The second reason is that most developers know and understand MVC. When you need to pass your code on to another developer, or when you work together, it helps to have clear communication. Using the standard MVC is one way to make sure this transition and collaboration goes smoothly.

A third reason to use MVC – one that’s often overlooked – is that it gives you confidence as a developer. You can’t lose sleep over worrying whether your code is structured OK if you use Model-View-Controller, or… at least you worry less than you would if you hadn’t used any structure!

Model-View-Controller also increases the modularity of your code, and aids code reuse. According to the Don’t Repeat Yourself (DRY) principle, you want to avoid duplicating similar lines of code as much as possible.

Object-Oriented Programming already helps with that. Instead of creating a bunch of variables to organize tweets, for instance, you can create a Tweet class and assign it title and user properties.

In your app you often represent data in visually similar ways, even if the data is different. It doesn’t matter if you’re showing a tweets timeline, a profile’s tweets or trending tweets – the tweets and their UI stays the same.

Combining OOP and MVC means that you’d create a TweetViewController that can display any assortment of tweets, instead of creating a separate FavoriteTweetViewController and ProfileTweetController. Less repeating, more code reuse!

Learn how to code your own iOS apps by mastering Swift 5 and Xcode 11 » Find out how

Practical Uses in iOS Development

Unfortunately, the Model-View-Controller architecture on iOS has one large caveat: it’s often abstracted away!

Let’s say you would build a chat app, much like the chat app from this iOS coding tutorial. The chat app uses Firebase, a popular cloud-based back-end platform.

The chat app uses a ChatViewController, a Controller component. In that controller you find the following code:

let query = Constants.refs.databaseChats.queryLimited(toLast: 10)

_ = query.observe(.childAdded, with: { [weak self] snapshot in

    // Append the chat message to the `messages` property ...
    // ... then update the messages view controller

So far so good! This is clearly a Model observation. You’re attaching the view controller to a particular Firebase query, so that when the data on the back-end changes, you get updates in the view controller.

But then… inside the observe callback, i.e. what happens when new messages come in, you add the new message to the messages property of the view controller. The view controller uses a table view (from UIKit) to display cells on screen – one cell per chat message. Are those Views?

You can imagine it’s easy to lose track of Model-View-Controller in practical app development. Why aren’t the chat messages called Models?

Is the ChatViewController class a Model, a View or a Controller? After all, it displays data, it manipulates it, and it also stores it with the messages property…

This is where theory meets practice. It’s good to know that in practical iOS development, the roles of Model, View and Controller sometimes overlap.

Nevertheless, you should be able to distinguish these roles in your app. Some examples from the chat app:

  • The Firebase back-end, with its data structures, clearly has the Model role
  • The ChatViewController, a collection view controller subclass, with its logic and commands, clearly has the Controller role
  • The chat message views, that are collection view cells, clearly have the View role

Oftentimes, it’s the Controller that has the most overlap with other roles. It’s not an accident that in iOS development it’s called “View Controller”, i.e. a Controller that also is (partly) a View.

Likewise, many of the parts of the app are Model-View-Controller components themselves. A UIButton is a View, and the messages property contains instances of class JSQMessage, which is a Model.

This fuzzy role of the Controller is often called Model-View-Whatever (MVW), simply to indicate that practical development doesn’t have a black-and-white Controller component. The code is the controller.

Further Reading

So, what should you take away from this?

There’s one thing that never changes, the whole reason you use Model-View-Controller: the messages. Data still flows from one side of the app to another side, and it still does that in just two ways:

  • Data from the Model that updates the View (Model → View)
  • User interaction from the View that updates the Model (View → Model)

Both data flows go through the Controller, which in turn decide what should happen with the data. Neat, right?

Want to learn more? Check out these resources:

Enjoyed this article? Please share it!

Reinder de Vries

Reinder de Vries

Reinder de Vries is a professional iOS developer. He teaches app developers how to build their own apps at LearnAppMaking.com. Since 2009 he has developed a few dozen apps for iOS, worked for global brands and lead development at several startups. When he’s not coding, he enjoys strong espresso and traveling.