DZone
Mobile Zone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
  • Refcardz
  • Trend Reports
  • Webinars
  • Zones
  • |
    • Agile
    • AI
    • Big Data
    • Cloud
    • Database
    • DevOps
    • Integration
    • IoT
    • Java
    • Microservices
    • Open Source
    • Performance
    • Security
    • Web Dev
DZone > Mobile Zone > Using the MVVM Design Pattern in iOS

Using the MVVM Design Pattern in iOS

The MVVM design pattern can be used to simplify the implementation of a custom table view cell and help promote clear design.

Greg Brown user avatar by
Greg Brown
·
Feb. 21, 17 · Mobile Zone · Opinion
Like (6)
Save
Tweet
7.14K Views

Join the DZone community and get the full member experience.

Join For Free

MVVM (model/view/view-model) is design pattern that helps promote a separation of concerns in software development. It is an extension of the well-known model/view/controller (MVC) pattern that is often used in user interface design.

In a traditional MVC application, a controller object is used to mediate the interaction between two other objects known as the "model" and the "view." The model is an abstract representation of data managed by the application, and the view is a visual representation of the data contained in the model. The controller notifies the view of changes to the model and updates the model in response to user input events received from the view.

MVVM expands on MVC by further decoupling the view from the controller. Instead of requiring the controller to explicitly manage the view's state, a view in an MVVM application uses data binding to be automatically updated in response to changes in a "view model" object exposed by the controller. This object adapts the data provided by the underlying model so that it can be easily consumed by the view. The additional level of indirection allows the view and controller to vary independently without the risk of breaking one or the other.

MVC Example

For example, consider a simple custom table view cell implemented using MVC:

The cell class might provide a set of outlets that the table view controller can use to update its state:

class CustomCell: UITableViewCell {
    @IBOutlet var headingLabel: UILabel!
    @IBOutlet var detailLabel: UILabel!

    ...
}

The controller would use the outlets to populate the cell's contents when a new cell is requested. In this example, row data is provided by dictionary instances containing "heading" and "detail" values for each cell:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let row = rows[indexPath.row]

    let cell = tableView.dequeueReusableCell(withIdentifier: "customCell") as! CustomCell

    cell.headingLabel.text = row["heading"] as? String
    cell.detailLabel.text = row["detail"] as? String

    return cell
}

However, this design creates a tight coupling between the controller and the custom cell view. Any time the view class changes, the controller must also be updated.

MVVM Example

MVVM solves this problem by decoupling the view from the controller. Rather than exposing its implementation details via outlets, the view registers itself as an observer on the properties of the view model. Using this approach, the view and controller both become dependent on the view model, but neither is dependent on the other. As long as the view model doesn't change, either one can be modified without impact.

For example, the following markup shows a custom table view cell implemented using MarkupKit, an open-source framework for building native iOS and tvOS applications using a simple HTML-like markup language. The cell contains two labels arranged vertically in a column:

<root accessoryType="disclosureIndicator">
    <LMColumnView>
        <UILabel class="label.heading" text="$content.heading"/>
        <UILabel class="label.detail" text="$content.detail"/>
    </LMColumnView>
</root>

Instead of outlets, the custom cell class exposes a content property representing the view model. The labels' text properties are bound to the properties of this object:

class CustomCell: LMTableViewCell {
    // View model
    dynamic var content: [String: AnyObject]?

    ...    
}

With the bindings established, the controller can be implemented as shown below. It simply dequeues a cell and sets its content property to the dictionary for the corresponding row. Because they are bound to the properties of the view model, the cell's labels are automatically updated to reflect the new values. No direct manipulation of view elements is required:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "customCell") as! CustomCell

    cell.content = rows[indexPath.row]

    return cell
}

Summary

This article introduced the MVVM design pattern and provided an example of how it can be used to simplify the implementation of a custom table view cell. The complete source code for the example can be found here.

For more information, see the MarkupKit README.

Design Database

Published at DZone with permission of Greg Brown, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • Major PostgreSQL Features You Should Know About
  • What's the Difference Between Static Class vs. Singleton Patterns in C#?
  • What Software Developers Can Learn From Andy Warhol
  • Spring, IoC Containers, and Static Code: Design Principles

Comments

Mobile Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • MVB Program
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends:

DZone.com is powered by 

AnswerHub logo