Git Product home page Git Product logo

cellviewmodel's Introduction

Swift Xcode MIT CocoaPods Compatible

CellViewModel

Using CellViewModel to configure you UITableViewCell or UICollectionViewCell is just a one possible approach of work with UIKit's collections.

Requirements:

  • iOS 10.0+
  • Xcode 10.0+
  • Swift 4.2+

Installation

CocoaPods

target 'MyApp' do
  pod 'CellViewModel', '~> 1.1'
end

Carthage

github "AntonPoltoratskyi/CellViewModel" "master"

Usage

Works with UITableView & UICollectionView - one possible approach, inspired by CocoaHeads:

You can move configuration logic for UITableViewCell or UICollectionViewCell from -cellForRowAtIndexPath: to separate types.

  1. You need to create cell class and appropriate type that conforms to CellViewModel type:
public typealias AnyViewCell = UIView

public protocol CellViewModel: AnyCellViewModel {
    associatedtype Cell: AnyViewCell
    func setup(cell: Cell)
}

UserTableViewCell.swift

import CellViewModel

// MARK: - View Model

struct UserCellModel: CellViewModel {
    var user: User
    
    func setup(cell: UserTableViewCell) {
        cell.nameLabel.text = user.name
    }
}

// MARK: - Cell

final class UserTableViewCell: UITableViewCell, XibInitializable {
    @IBOutlet weak var nameLabel: UILabel!
}
  1. After that you need to register created model type:

There are 2 options:

  • use register(nibModel:) if appropriate CellViewModel's Cell conforms to XibInitializable:
tableView.register(nibModel: UserCellModel.self)
  • otherwise use register(viewModel:):
tableView.register(viewModel: UserCellModel.self)
  1. Then store your models in array (or your custom datasource type):
private var users: [AnyCellViewModel] = []

AnyCellViewModel is a base protocol of CellViewModel. It's needed only in order to fix compiler limitation as you can use protocols with associatedtype only as generic constraints and can't write something like this:

private var users: [CellViewModel] = [] // won't compile
  1. UITableViewDataSource implementation is very easy, even if you have multiple cell types, because all logic are contained in our view models:
import CellViewModel

class ViewController: UIViewController {
    
    @IBOutlet weak var tableView: UITableView!
    
    private var users: [AnyCellViewModel] = []

    override func viewDidLoad() {
        super.viewDidLoad()
        users = User.testDataSource.map { UserCellModel(user: $0) }
        tableView.register(nibModel: UserCellModel.self)
    }
}

extension ViewController: UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return users.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        return tableView.dequeueReusableCell(withModel: tableModel(at: indexPath), for: indexPath)
    }
    
    private func tableModel(at indexPath: IndexPath) -> AnyCellViewModel {
        return users[indexPath.row]
    }
}
  1. Or use TableViewDataAdapter:
private lazy var adapter = TableViewDataAdapter(tableView: self.tableView)

assign it as UITableView's dataSource:

override func viewDidLoad() {
    super.viewDidLoad()
    self.tableView.dataSource = adapter
}

updating data property will cause reloadData()

func setup(users: [AnyCellViewModel]) {
    adapter.data = users
}

Accessibility

Sometimes there is a need to define accessibilityIdentifier for UI testing purposes.

There is Accessible protocol that is conformed by CellViewModel protocol.

public protocol Accessible {
    var accessibilityIdentifier: String? { get }
    var accessibilityOptions: AccessibilityDisplayOptions { get }
}

So you need to define accessibilityIdentifier property in your model type implementation:

struct UserCellModel: CellViewModel {

    var accessibilityIdentifier: String? {
        return "user_cell"
    }

    // ...
}

And define accessibilityOptions if needed to add index path as suffix in the end of accessibilityIdentifier:

struct UserCellModel: CellViewModel {

    var accessibilityIdentifier: String? {
        return "user_cell"
    }
    
    var accessibilityOptions: AccessibilityDisplayOptions {
        return [.row, .section]
    }

    // ...
}

License

CellViewModel is available under the MIT license. See the LICENSE file for more info.

cellviewmodel's People

Contributors

devpolant avatar

Stargazers

MohsinAli avatar

Watchers

MohsinAli avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.