UITableView with MVVM using Swift

Viewed 16170

I'm working on MVVM architecture in Swift with UITableView. For this, I have created sample table view.

Can any one please suggest whether I am going correct or any other improvements need to do?

The following are the classes for this architecture.

  1. ViewController - Contains UITableView and its delegate and datasource methods.

    class ViewController: UIViewController {
        let PRODUCT_CELL_IDENTIFIER = "ProductCellIdentifier"
    
        @IBOutlet weak var productTableView: UITableView!
    
        var productViewModel: ProductViewModel = ProductViewModel()
    }
    
    //UITableView Delegate Methods
    extension ViewController {
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return productViewModel.numberOfRowsInSection()
        }
    
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: PRODUCT_CELL_IDENTIFIER) as! ProductTableViewCell
            let product = productViewModel.productsArray[indexPath.row]
            cell.productName.text = product.name
            cell.productQuantity.text = "\(product.quantity)"
            return cell
        }
    }
    
  2. ProductViewModel: - This is ViewModel class.

    class ProductViewModel: NSObject {
        var productsArray = Array<Product>()
    
        override init() {
            let product1 = Product(name: "Prodcut1", image_url: "", quantity: 2)
            let product2 = Product(name: "Prodcut2", image_url: "", quantity: 3)
            productsArray.append(product1)
            productsArray.append(product2)
        }
    
        func numberOfRowsInSection() -> Int {
            return productsArray.count
        }
    }
    
  3. Product - This is the model class

    class Product: NSObject {
        var name: String
        var image_url: String
        var quantity: Int
    
        init(name: String, image_url: String, quantity: Int) {
            self.name = name
            self.image_url = image_url
            self.quantity = quantity
        }
    }
    
  4. ProductTableViewCell - This is UITableViewCell class

    class ProductTableViewCell: UITableViewCell {
        @IBOutlet weak var productQuantity: UILabel!
        @IBOutlet weak var productName: UILabel!
        @IBOutlet weak var productImageView: UIImageView!
    }
    
2 Answers

MVVM in iOS can be easily implemented without using third party dependencies. For data binding, we can use a simple combination of Closure and didSet to avoid third-party dependencies.

public final class Observable<Value> {

    private var closure: ((Value) -> ())?

    public var value: Value {
        didSet { closure?(value) }
    }

    public init(_ value: Value) {
        self.value = value
    }

    public func observe(_ closure: @escaping (Value) -> Void) {
        self.closure = closure
        closure(value)
    }
}

An example of data binding from ViewController:

final class ExampleViewController: UIViewController {

    private func bind(to viewModel: ViewModel) {
        viewModel.items.observe(on: self) { [weak self] items in
            self?.tableViewController?.items = items
            // self?.tableViewController?.items = viewModel.items.value // This would be Momory leak. You can access viewModel only with self?.viewModel
        }
        // Or in one line:
        viewModel.items.observe(on: self) { [weak self] in self?.tableViewController?.items = $0 }
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        bind(to: viewModel)
        viewModel.viewDidLoad()
    }
}

protocol ViewModelInput {
    func viewDidLoad()
}

protocol ViewModelOutput {
    var items: Observable<[ItemViewModel]> { get }
}

protocol ViewModel: ViewModelInput, ViewModelOutput {}
final class DefaultViewModel: ViewModel {  
  let items: Observable<[ItemViewModel]> = Observable([])

  // Implmentation details...
}

Later it can be replaced with SwiftUI and Combine (when a minimum iOS version of your app is 13)

In this article, there is a more detailed description of MVVM https://tech.olx.com/clean-architecture-and-mvvm-on-ios-c9d167d9f5b3

Related