Embarking on My iOS App Development Journey

As you may already guess from a title on my website’s main page I’m a Full Stack Web Developer with vast experience in the .NET Framework and Microsoft Technologies. On the other hand, I excel in most applications that exploit modern JavaScript frameworks, such as Angular and React. The strong pull for developing mobile applications only remained a dream to me, thus developed deep exploration of potential possibilities that would see some of my applications grace the App Store.

It is always complex for most of the beginners at the start. One area that I am actually having a real problem with is deciding on the best design pattern to use in developing the iOS app. In the course of my research, I have managed to identify two of the most used design patterns, namely MVVM (Model View ViewModel) and VM (ViewModel).

Exploring iOS Design Patterns: MVVM Versus VM

What exactly is a design pattern, and why should we pay attention to it? Let’s begin by defining what a design pattern is. A design pattern constitutes best practices for a common design problem. It is typically expressed as relationships between classes and objects. Now, let’s dive in and attempt to comprehend its real-world applications and use cases.

Design patterns are essential for:

  • Establishing Best Practices
  • Facilitating the Relationship Between Classes and Objects
  • Accelerating Development Process
  • Ensuring Programming Independence

There are two design patterns I would like to focus on and analyze in detail: MVVM and MV. Let’s break down the MV design pattern first.

MV Design Pattern Break Down

In the MV pattern, we don’t explicitly separate the business logic and presentation logic as cleanly as MVVM. Instead, the View directly interacts with the Model. This approach is less common in SwiftUI but personally I really like, here is an example below.

import SwiftUI

// Model
struct Post: Decodable, Identifiable {
    let id: Int
    let title: String
    let body: String
}

// View
struct PostsView: View {
    @State private var posts: [Post] = []

    var body: some View {
        List(posts) { post in
            VStack(alignment: .leading) {
                Text(post.title).fontWeight(.bold)
                Text(post.body)
            }
        }
        .onAppear {
            fetchPosts()
        }
    }

    func fetchPosts() {
        guard let url = URL(string: "https://jsonplaceholder.typicode.com/posts") else { return }

        URLSession.shared.dataTask(with: url) { data, _, _ in
            let posts = try? JSONDecoder().decode([Post].self, from: data ?? Data())
            DispatchQueue.main.async {
                self.posts = posts ?? []
            }
        }.resume()
    }
}

Careful observation of the given structure of the code clearly reveals that it is very close to the structure of a React component that is generally considered more mature than that of a SwiftUI. Most of the developers will easily notice such an observation, as the boilerplate code is greatly reduced. This not only simplifies the development but also makes the transition easy for one who has worked with MV design pattern already that is already buit in many Javascript libraries and frameworks.

See example of the binding that already exist in the MV pattern on the image below MV design pattern binding

MVVM Design Pattern Breakdown

The MVVM pattern involves creating a ViewModel that handles data fetching and business logic, separating these concerns from the View.

import SwiftUI
// Model
struct Post: Decodable, Identifiable {
    let id: Int
    let title: String
    let body: String
}

// ViewModel
class PostsViewModel: ObservableObject {
    @Published var posts: [Post] = []

    func fetchPosts() {
        guard let url = URL(string: "https://jsonplaceholder.typicode.com/posts") else { return }

        URLSession.shared.dataTask(with: url) { data, _, _ in
            let posts = try? JSONDecoder().decode([Post].self, from: data ?? Data())
            DispatchQueue.main.async {
                self.posts = posts ?? []
            }
        }.resume()
    }
}

// View
struct PostsView: View {
    @ObservedObject var viewModel = PostsViewModel()

    var body: some View {
        List(viewModel.posts) { post in
            VStack(alignment: .leading) {
                Text(post.title).fontWeight(.bold)
                Text(post.body)
            }
        }
        .onAppear {
            viewModel.fetchPosts()
        }
    }
}

You can see that while using the MVVM pattern we have one more extra class where we put our logic to fetch the data and do the property binding. The benefit of such is we have the logic separated from the view but we are missing on some important Swift UI property wrappers that can’t be used or are difficult to use including:

  • @FocusState
  • @GestureState
  • @FetchRequest
  • @SectionedFetchRequest
  • @EnvironmentObject

Here is the graph diagram illustrating the MVVM design pattern in iOS MVVM design pattern diagram

We can conclude that in many scenarios, the ViewModel pattern introduces an additional layer that may be unnecessary and can be omitted. Evidently, the optimal design pattern is the one that addresses your specific problems efficiently, is well-structured, and can be readily understood and adopted by other developers. For the application I am currently developing, I have chosen the MV pattern, as it aligns perfectly with my needs and offers enhanced clarity, especially considering my prior experience with React and React Native.

Useful links: