UITableView with MVVM using Swift
You are doing good job, but you can even improve you product model with adding following function to get array of direct models. It is very useful when you have create array from web Api response.
class Product : NSObject { var imgUrl : String! var name : String! var quantity : Int! init(dictionary: [String:Any]) { imgUrl = dictionary["img_url"] as? String name = dictionary["name"] as? String quantity = dictionary["quantity"] as? Int } init(name: String, image_url: String, quantity: Int) { self.name = name self.imgUrl = image_url self.quantity = quantity } public class func modelsFromArray(array:[[String:Any]]) -> [Product] { var models:[Product] = [] for item in array { models.append(Product.init(dictionary:item)) } return models } }
With Usage Like
let product1 = Product(name: "Prodcut1", image_url: "", quantity: 2) //Normal Case let productList:[[String:Any]] = [ ["name":"Jaydeep","img_url":"xyz","quantity":1], ["name":"Jaydeep","img_url":"xyz","quantity":2], ["name":"Jaydeep","img_url":"xyz","quantity":3], ["name":"Jaydeep","img_url":"xyz","quantity":4], ["name":"Jaydeep","img_url":"xyz","quantity":5], ["name":"Jaydeep","img_url":"xyz","quantity":6] ] //Assign Direct Dictionary to Get Array Of Models/* Very useful when productList is dictionary from server response*/ let productArray:[Product] = Product.modelsFromArray(array: productList)
And Also your Cell Class is Improved By
class ProductTableViewCell: UITableViewCell {@IBOutlet weak var productQuantity: UILabel!@IBOutlet weak var productName: UILabel!@IBOutlet weak var productImageView: UIImageView!func setProductData(product:Product){ self.productName.text = product.name self.productQuantity.text = "\(product.quantity)"}}
Usage:
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.setProductData(product:product) return cell }
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 MVVMhttps://tech.olx.com/clean-architecture-and-mvvm-on-ios-c9d167d9f5b3