Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

lightweight wrapper for UICollectionViewDataSource/Delegate and UITableViewDataSource/Delegate

License

NotificationsYou must be signed in to change notification settings

stanwood/SourceModel_iOS

Repository files navigation

banner

Swift VersioniOS 9+MaintainabilityBuild Status

SourceModel is alightweight wrapper forUICollectionViewDataSource/Delegate andUITableViewDataSource/Delegate. It removes the burden of writing the boiler plate code when working withtableViews andcollectionViews, allowing you to focus on what's important, populating the cells with data.

SourceModdel focus onSeperation of Concern, where the cell should only be accessible to get the data to present and decide how to present it. ThedataSource should not be responsible for deciding how the cell should populate its data, nor know about the view.

Usage

Let's jump into some of the protocols you need to be familiar with, to get started. Let's think of a view, that shows products:

ModelCollection protocol

ModelCollection represent a collection of similar items, the products in our case.

publicprotocolModelCollection{        /// Returns the number of itemsvarnumberOfItems:Int{get}        /// Returns the number of sectionsvarnumberOfSections:Int{get}        /// A subscript to return a type in an indexPath    subscript(indexPath:IndexPath)->Model?{get}        /// A subscript to return a collection dataType within a section    subscript(section:Int)->ModelCollection{get}        /// Returns the cell type at indexPathfunc cellType(forItemAt indexPath:IndexPath)->Fillable.Type?}

Model protocol

Model represents a single item in a collection of item, a product.

Both in action

Let's create a collection of items to see it in action:

We will dive into theFillable protocol in a later stage, for now, let's assume we have aProductCell.

structProduct{...}structProducts:ModelCollection{letitems:[Product]varnumberOfItems:Int{return items.count}varnumberOfSections:Int{return1}        subscript(indexPath:IndexPath)->Model?{returnitems[indexPath.row]}        subscript(section:Int)->ModelCollection{returnself}func cellType(forItemAt indexPath:IndexPath)->Fillable.Type?{returnProductCell.self}}

Ok, this is cool, but we can make it even simpler.SourceModel offers anElements class that wrapps the above, where you only need to take care of the cells. This is how it works:

class Products: Elements<Product>, Codable {   func cellType(forItemAt indexPath: IndexPath) -> Fillable.Type? {    return ProductCell.self    }}

Now that we we finalised our collection, let's create an instance ofProducts:

letproducts=Products(items:[Product(),Product()])

Fillable protocol

Each cell must conform to theFillable protocol. This is where your model is injected, and where you will populate the cell.

class ProductCell:UICollectionViewCell,Fillable{....func fill(with model:Model?){guardlet product= modelas?Productelse{return}/// Handle product}}

Preparing the DataSource and Delegate

Now that we have the model, modelCollection, and the cell, let's create theDataSource andDelegate

classProductsViewController:UIViewController{vardataSource:CollectionDataSource! /// Use TableDataSource for UITableViewvardelegate:CollectionDelegate! /// Use TableDelegate for UITableViewletproducts=Products(items:[Product(),Product()])overridefunc viewDidLoad(){      super.viewDidLoad()setupCollectionView(with: products)}privatefunc setupCollectionView(with modelCollection:ModelCollection?)      delegate= CollectionDataSource(modelCollection:modelCollection)      dataSource= CollectionDelegate(modelCollection:modelCollection)              collectionView.register(cellType:ProductCell.self)              collectionView.delegate= delegate      collectionView.dataSource= dataSource}}

Note: To get theregister(cellType:) function, addStanwoodCore to your project.

That's it! 😊

You are probably wondering where to go from here? Let's look at a more complex cases, and howSourceModel can help you.

Working withSections

Working with sections can be a tedious task. You can useModelCollection and inject a collection of sections (otherModelCollections). Alternatively,SourceModel offersSections. Let's look at ourProducts elements from before, and migrate it to sections of different product categories

classProductsViewController:UIViewController{vardataSource:CollectionDataSource! /// Use TableDataSource for UITableViewvardelegate:CollectionDelegate! /// Use TableDelegate for UITableViewletsections:Sections!overridefunc viewDidLoad(){      super.viewDidLoad()letbeautyProducts=Products(items:[Product(),Product()])letgroceryProducts=Products(items:[Product(),Product()])      sections=Sections(sections:[beautyProducts, groceryProducts])setupCollectionView(with: products)}privatefunc setupCollectionView(with modelCollection:ModelCollection?)      delegate= CollectionDataSource(modelCollection:modelCollection)      dataSource= CollectionDelegate(modelCollection:modelCollection)              collectionView.register(cellType:ProductCell.self)              collectionView.delegate= delegate      collectionView.dataSource= dataSource}}

Working withHeaders

If you want to add a section header, make sure youModelCollection conforms toHeaderable. You have a couple of optional options, depending weather you are populating acollectionView or atableView.

Headerable

/// Headerable protocol to add header support for `UICollectionView` and `UITableView`@objcpublicprotocolHeaderable{        /// `UITableView` section header view@objcoptionalvarheaderView:UIView{get}        /// `UICollectionView` header reusable header view@objcoptionalvarreusableView:UICollectionReusableView{get}}

Example

Let's take ourProducts and add a header

classProducts:Elements<Product>,Codable,Headerable{varheaderView:UIView{letview=CategoryHeaderView.loadFromNib()       view?.backgroundColor=.clear       view?.set(title: title)return view??UIView()}...}

Note: To get theloadFromNib() function, addStanwoodCore to your project

Important!

Known issue: At this stage,ModelCollection does not support reusable header views. This is under development. To avoid any memory issues, you should useHeaderable only for a single header view.

ImplementingDelegate pattern

To work with theDelegate Design Pattern,SourceModel offers aDelegateable protocol. Let's see how that works with ourProductCell:

Example: Cell

protocolProductCellDelegate:class{func productCellDidDoSomething(with product:Product)}/// Conform to `Delegateable`classProductCell:UICollectionViewCell,Fillable,Delegateable{private weakvardelegate:ProductCellDelegate?..../// Set the delegatefunc set(delegate:AnyObject){self.delegate= delegateas?ProductCellDelegate}@IBAction didTapSomeButton(_ sender: UIButton){   delegate?.productCellDidDoSomething(with: product)}}

**Example: ViewController

classProductsViewController:UIViewController{vardataSource:CollectionDataSource! /// Use TableDataSource for UITableViewvardelegate:CollectionDelegate! /// Use TableDelegate for UITableViewletproducts=Products(items:[Product(),Product()])overridefunc viewDidLoad(){      super.viewDidLoad()setupCollectionView(with: products)}privatefunc setupCollectionView(with modelCollection:ModelCollection?)         delegate= CollectionDataSource(modelCollection:modelCollection)            /// Inject `self` as the delegate      dataSource= CollectionDelegate(modelCollection:modelCollection, delegate:self)              collectionView.register(cellType:ProductCell.self)              collectionView.delegate= delegate      collectionView.dataSource= dataSource}}extension ProductsViewController: ProductCellDelegate{func productCellDidDoSomething(with product:Product){/// Do something with product}}

Working with cell index's

In some cases, we require to know at what index the cell is positioned. Conform toIndexable protocol to get the index.

Example

class ProductCell:UICollectionViewCell,Fillable,Indexable{....func inject(_ indexPath:IndexPath){/// Do something with the index}}

Roadmap

  • Adding support fordelegate patter
  • Adding support forheaders
  • AddingIndexable protocol to inject theindexPath into the cell
  • Adding areloadData(animated:) that reloads the models that changed
  • Adding generics toFillable protocol
  • Adding reusableHeader/Footer view
  • AddingSwiftUI support
  • AddingCombine support

Please open an issue for feature requests.

Example

To run the example project, clone the repo, and runpod install from the Example directory first.

Requirements

Installation

SourceModel is available throughCocoaPods. To installit, simply add the following line to your Podfile:

pod'SourceModel'

Author

Tal Zion,tal.zion@stanwood.de

License

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

About

lightweight wrapper for UICollectionViewDataSource/Delegate and UITableViewDataSource/Delegate

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors2

  •  
  •  

[8]ページ先頭

©2009-2026 Movatter.jp