简体   繁体   中英

UITableView with MVVM using Swift

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! }

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 MVVM https://tech.olx.com/clean-architecture-and-mvvm-on-ios-c9d167d9f5b3

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM