Merge pull request #56 from maxsokolov/actions_improvements

Support multiple actions with same type
This commit is contained in:
Max Sokolov 2016-10-23 12:52:09 +03:00 committed by GitHub
commit 934e7623f9
14 changed files with 263 additions and 135 deletions

View File

@ -2,8 +2,15 @@
All notable changes to this project will be documented in this file.
## [2.0.0](https://github.com/maxsokolov/TableKit/releases/tag/1.4.0)
Released on 2016-09-06. Breaking changes in 2.0.0:
## [2.1.0](https://github.com/maxsokolov/TableKit/releases/tag/1.4.0)
Released on 2016-10-19.
- `action` method was deprecated on TableRow. Use `on` instead.
- Support multiple actions with same type on row.
- You could now build your own cell height calculating strategy. See [TablePrototypeCellHeightCalculator](Sources/TablePrototypeCellHeightCalculator.swift).
- Default distance between sections changed to `UITableViewAutomaticDimension`. You can customize it, see [TableSection](Sources/TableSection.swift)
## [2.0.0](https://github.com/maxsokolov/TableKit/releases/tag/2.0.0)
Released on 2016-10-06. Breaking changes in 2.0.0:
<br/>The signatures of `TableRow` and `TableRowAction` classes were changed from
```swift
let action = TableRowAction<String, StringTableViewCell>(.click) { (data) in

View File

@ -23,9 +23,9 @@ class MainController: UIViewController {
title = "TableKit"
let clickAction = TableRowAction<ConfigurableTableViewCell>(.click) { [weak self] (data) in
let clickAction = TableRowAction<ConfigurableTableViewCell>(.click) { [weak self] (options) in
switch (data.indexPath as NSIndexPath).row {
switch options.indexPath.row {
case 0:
self?.performSegue(withIdentifier: "autolayoutcells", sender: nil)
case 1:
@ -34,11 +34,16 @@ class MainController: UIViewController {
break
}
}
let printClickAction = TableRowAction<ConfigurableTableViewCell>(.click) { (options) in
print("click", options.indexPath)
}
let rows = [
TableRow<ConfigurableTableViewCell>(item: "Autolayout cells", actions: [clickAction]),
TableRow<ConfigurableTableViewCell>(item: "Nib cells", actions: [clickAction])
TableRow<ConfigurableTableViewCell>(item: "Autolayout cells", actions: [clickAction, printClickAction]),
TableRow<ConfigurableTableViewCell>(item: "Nib cells", actions: [clickAction, printClickAction])
]
// automatically creates a section, also could be used like tableDirector.append(rows: rows)

View File

@ -21,12 +21,13 @@ class NibCellsController: UITableViewController {
tableDirector = TableDirector(tableView: tableView)
let numbers = [1000, 2000, 3000, 4000, 5000]
let shouldHighlightAction = TableRowAction<NibTableViewCell>(.shouldHighlight) { (_) -> Bool in
return false
}
let rows = numbers.map { TableRow<NibTableViewCell>(item: $0, actions: [shouldHighlightAction]) }
let rows = numbers.map {
TableRow<NibTableViewCell>(item: $0)
.on(.shouldHighlight) { (_) -> Bool in
return false
}
}
tableDirector.append(rows: rows)
}

View File

@ -4,7 +4,7 @@
<a href="https://travis-ci.org/maxsokolov/TableKit"><img src="https://api.travis-ci.org/maxsokolov/TableKit.svg" alt="Build Status" /></a>
<a href="https://developer.apple.com/swift"><img src="https://img.shields.io/badge/Swift_3.0-compatible-4BC51D.svg?style=flat" alt="Swift 3.0 compatible" /></a>
<a href="https://github.com/Carthage/Carthage"><img src="https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat" alt="Carthage compatible" /></a>
<a href="https://cocoapods.org/pods/tablekit"><img src="https://img.shields.io/badge/pod-2.0.0-blue.svg" alt="CocoaPods compatible" /></a>
<a href="https://cocoapods.org/pods/tablekit"><img src="https://img.shields.io/badge/pod-2.1.0-blue.svg" alt="CocoaPods compatible" /></a>
<img src="https://img.shields.io/badge/platform-iOS-blue.svg?style=flat" alt="Platform iOS" />
<a href="https://raw.githubusercontent.com/maxsokolov/tablekit/master/LICENSE"><img src="http://img.shields.io/badge/license-MIT-blue.svg?style=flat" alt="License: MIT" /></a>
</p>
@ -84,13 +84,14 @@ You could have as many rows and sections as you need.
It nice to have some actions that related to your cells:
```swift
let action = TableRowAction<StringTableViewCell>(.click) { (data) in
let action = TableRowAction<StringTableViewCell>(.click) { (options) in
// you could access any useful information that relates to the action
// data.cell - StringTableViewCell?
// data.item - String
// data.indexPath - IndexPath
// options.cell - StringTableViewCell?
// options.item - String
// options.indexPath - IndexPath
// options.userInfo - [AnyHashable: Any]?
}
let row = TableRow<StringTableViewCell>(item: "some", actions: [action])
@ -98,10 +99,10 @@ let row = TableRow<StringTableViewCell>(item: "some", actions: [action])
Or, using nice chaining approach:
```swift
let row = TableRow<StringTableViewCell>(item: "some")
.action(.click) { (data) in
.on(.click) { (options) in
}
.action(.shouldHighlight) { (data) -> Bool in
.on(.shouldHighlight) { (options) -> Bool in
return false
}
```
@ -126,10 +127,29 @@ class MyTableViewCell: UITableViewCell, ConfigurableCell {
```
And handle them accordingly:
```swift
let myAction = TableRowAction<MyTableViewCell>(.custom(MyActions.ButtonClicked)) { (data) in
let myAction = TableRowAction<MyTableViewCell>(.custom(MyActions.ButtonClicked)) { (options) in
}
```
## Multiple actions with same type
It's also possible to use multiple actions with same type:
```swift
let click1 = TableRowAction<StringTableViewCell>(.click) { (options) in }
click1.id = "click1" // optional
let click2 = TableRowAction<StringTableViewCell>(.click) { (options) in }
click2.id = "click2" // optional
let row = TableRow<StringTableViewCell>(item: "some", actions: [click1, click2])
```
Could be useful in case if you want to separate your logic somehow. Actions will be invoked in order which they were attached.
> If you define multiple actions with same type which also return a value, only last return value will be used for table view.
You could also remove any action by id:
```swift
row.removeAction(forActionId: "action_id")
```
# Advanced
@ -149,7 +169,7 @@ It's enough for most cases. But you may be not happy with this. So you could use
```swift
tableDirector.shouldUsePrototypeCellHeightCalculation = true
```
It does all dirty work with prototypes for you [behind the scene](Sources/HeightStrategy.swift), so you don't have to worry about anything except of your cell configuration:
It does all dirty work with prototypes for you [behind the scene](Sources/TablePrototypeCellHeightCalculator.swift), so you don't have to worry about anything except of your cell configuration:
```swift
class ImageTableViewCell: UITableViewCell, ConfigurableCell {

View File

@ -20,10 +20,6 @@
import UIKit
struct TableKitNotifications {
static let CellAction = "TableKitNotificationsCellAction"
}
/**
A custom action that you can trigger from your cell.
You can easily catch actions using a chaining manner with your row.

View File

@ -29,13 +29,15 @@ open class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate {
open private(set) var sections = [TableSection]()
private weak var scrollDelegate: UIScrollViewDelegate?
private var heightStrategy: CellHeightCalculatable?
private var cellRegisterer: TableCellRegisterer?
public var rowHeightCalculator: RowHeightCalculator?
open var shouldUsePrototypeCellHeightCalculation: Bool = false {
didSet {
if shouldUsePrototypeCellHeightCalculation {
heightStrategy = PrototypeHeightStrategy(tableView: tableView)
rowHeightCalculator = TablePrototypeCellHeightCalculator(tableView: tableView)
} else {
rowHeightCalculator = nil
}
}
}
@ -50,7 +52,7 @@ open class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate {
if shouldUseAutomaticCellRegistration {
self.cellRegisterer = TableCellRegisterer(tableView: tableView)
}
self.scrollDelegate = scrollDelegate
self.tableView = tableView
self.tableView?.delegate = self
@ -70,8 +72,8 @@ open class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate {
// MARK: Public
@discardableResult
open func invoke(action: TableRowActionType, cell: UITableViewCell?, indexPath: IndexPath) -> Any? {
return sections[indexPath.section].rows[indexPath.row].invoke(action, cell: cell, path: indexPath)
open func invoke(action: TableRowActionType, cell: UITableViewCell?, indexPath: IndexPath, userInfo: [AnyHashable: Any]? = nil) -> Any? {
return sections[indexPath.section].rows[indexPath.row].invoke(action: action, cell: cell, path: indexPath, userInfo: userInfo)
}
open override func responds(to selector: Selector) -> Bool {
@ -85,33 +87,34 @@ open class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate {
// MARK: - Internal -
func hasAction(_ action: TableRowActionType, atIndexPath indexPath: IndexPath) -> Bool {
return sections[indexPath.section].rows[indexPath.row].hasAction(action)
return sections[indexPath.section].rows[indexPath.row].has(action: action)
}
func didReceiveAction(_ notification: Notification) {
guard let action = notification.object as? TableCellAction, let indexPath = tableView?.indexPath(for: action.cell) else { return }
invoke(action: .custom(action.key), cell: action.cell, indexPath: indexPath)
invoke(action: .custom(action.key), cell: action.cell, indexPath: indexPath, userInfo: notification.userInfo)
}
// MARK: - Height
open func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
let row = sections[indexPath.section].rows[indexPath.row]
cellRegisterer?.register(cellType: row.cellType, forCellReuseIdentifier: row.reuseIdentifier)
return row.estimatedHeight ?? heightStrategy?.estimatedHeight(row, path: indexPath) ?? UITableViewAutomaticDimension
return row.estimatedHeight ?? rowHeightCalculator?.estimatedHeight(forRow: row, at: indexPath) ?? UITableViewAutomaticDimension
}
open func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let row = sections[indexPath.section].rows[indexPath.row]
if shouldUsePrototypeCellHeightCalculation {
cellRegisterer?.register(cellType: row.cellType, forCellReuseIdentifier: row.reuseIdentifier)
}
let rowHeight = invoke(action: .height, cell: nil, indexPath: indexPath) as? CGFloat
return rowHeight ?? row.defaultHeight ?? heightStrategy?.height(row, path: indexPath) ?? UITableViewAutomaticDimension
return rowHeight ?? row.defaultHeight ?? rowHeightCalculator?.height(forRow: row, at: indexPath) ?? UITableViewAutomaticDimension
}
// MARK: UITableViewDataSource - configuration
@ -127,6 +130,9 @@ open class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate {
open func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let row = sections[indexPath.section].rows[indexPath.row]
cellRegisterer?.register(cellType: row.cellType, forCellReuseIdentifier: row.reuseIdentifier)
let cell = tableView.dequeueReusableCell(withIdentifier: row.reuseIdentifier, for: indexPath)
if cell.frame.size.width != tableView.frame.size.width {
@ -163,13 +169,13 @@ open class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate {
open func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
let section = sections[section]
return section.headerHeight ?? section.headerView?.frame.size.height ?? 0
return section.headerHeight ?? section.headerView?.frame.size.height ?? UITableViewAutomaticDimension
}
open func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
let section = sections[section]
return section.footerHeight ?? section.footerView?.frame.size.height ?? 0
return section.footerHeight ?? section.footerView?.frame.size.height ?? UITableViewAutomaticDimension
}
// MARK: UITableViewDelegate - actions
@ -252,8 +258,7 @@ open class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate {
return self
}
@discardableResult
open func delete(index: Int) -> Self {
open func delete(sectionAt index: Int) -> Self {
sections.remove(at: index)
return self
@ -262,7 +267,19 @@ open class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate {
@discardableResult
open func clear() -> Self {
rowHeightCalculator?.invalidate()
sections.removeAll()
return self
}
// MARK: - deprecated methods -
@available(*, deprecated, message: "Use 'delete(sectionAt:)' method instead")
@discardableResult
open func delete(index: Int) -> Self {
sections.remove(at: index)
return self
}
}

86
Sources/TableKit.swift Normal file
View File

@ -0,0 +1,86 @@
//
// Copyright (c) 2015 Max Sokolov https://twitter.com/max_sokolov
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import UIKit
struct TableKitNotifications {
static let CellAction = "TableKitNotificationsCellAction"
}
public protocol RowConfigurable {
func configure(_ cell: UITableViewCell)
}
public protocol RowActionable {
var editingActions: [UITableViewRowAction]? { get }
func isEditingAllowed(forIndexPath indexPath: IndexPath) -> Bool
func invoke(action: TableRowActionType, cell: UITableViewCell?, path: IndexPath, userInfo: [AnyHashable: Any]?) -> Any?
func has(action: TableRowActionType) -> Bool
}
public protocol RowHashable {
var hashValue: Int { get }
}
public protocol Row: RowConfigurable, RowActionable, RowHashable {
var reuseIdentifier: String { get }
var cellType: AnyClass { get }
var estimatedHeight: CGFloat? { get }
var defaultHeight: CGFloat? { get }
}
public enum TableRowActionType {
case click
case clickDelete
case select
case deselect
case willSelect
case willDisplay
case shouldHighlight
case height
case canEdit
case configure
case custom(String)
var key: String {
switch (self) {
case .custom(let key):
return key
default:
return "_\(self)"
}
}
}
public protocol RowHeightCalculator {
func height(forRow row: Row, at indexPath: IndexPath) -> CGFloat
func estimatedHeight(forRow row: Row, at indexPath: IndexPath) -> CGFloat
func invalidate()
}

View File

@ -20,26 +20,18 @@
import UIKit
public protocol CellHeightCalculatable {
open class TablePrototypeCellHeightCalculator: RowHeightCalculator {
func height(_ row: Row, path: IndexPath) -> CGFloat
func estimatedHeight(_ row: Row, path: IndexPath) -> CGFloat
func invalidate()
}
open class PrototypeHeightStrategy: CellHeightCalculatable {
private weak var tableView: UITableView?
private(set) weak var tableView: UITableView?
private var prototypes = [String: UITableViewCell]()
private var cachedHeights = [Int: CGFloat]()
private var separatorHeight = 1 / UIScreen.main.scale
init(tableView: UITableView?) {
public init(tableView: UITableView?) {
self.tableView = tableView
}
open func height(_ row: Row, path: IndexPath) -> CGFloat {
open func height(forRow row: Row, at indexPath: IndexPath) -> CGFloat {
guard let tableView = tableView else { return 0 }
@ -71,7 +63,7 @@ open class PrototypeHeightStrategy: CellHeightCalculatable {
return height
}
open func estimatedHeight(_ row: Row, path: IndexPath) -> CGFloat {
open func estimatedHeight(forRow row: Row, at indexPath: IndexPath) -> CGFloat {
guard let tableView = tableView else { return 0 }

View File

@ -20,38 +20,10 @@
import UIKit
public protocol RowConfigurable {
func configure(_ cell: UITableViewCell)
}
public protocol RowActionable {
var editingActions: [UITableViewRowAction]? { get }
func isEditingAllowed(forIndexPath indexPath: IndexPath) -> Bool
func invoke(_ action: TableRowActionType, cell: UITableViewCell?, path: IndexPath) -> Any?
func hasAction(_ action: TableRowActionType) -> Bool
}
public protocol RowHashable {
var hashValue: Int { get }
}
public protocol Row: RowConfigurable, RowActionable, RowHashable {
var reuseIdentifier: String { get }
var cellType: AnyClass { get }
var estimatedHeight: CGFloat? { get }
var defaultHeight: CGFloat? { get }
}
open class TableRow<CellType: ConfigurableCell>: Row where CellType: UITableViewCell {
open let item: CellType.T
private lazy var actions = [String: TableRowAction<CellType>]()
private lazy var actions = [String: [TableRowAction<CellType>]]()
private(set) open var editingActions: [UITableViewRowAction]?
open var hashValue: Int {
@ -78,29 +50,32 @@ open class TableRow<CellType: ConfigurableCell>: Row where CellType: UITableView
self.item = item
self.editingActions = editingActions
actions?.forEach { self.actions[$0.type.key] = $0 }
actions?.forEach { on($0) }
}
// MARK: - RowConfigurable -
open func configure(_ cell: UITableViewCell) {
(cell as? CellType)?.configure(with: item)
}
// MARK: - RowActionable -
open func invoke(_ action: TableRowActionType, cell: UITableViewCell?, path: IndexPath) -> Any? {
return actions[action.key]?.invoke(item: item, cell: cell, path: path)
open func invoke(action: TableRowActionType, cell: UITableViewCell?, path: IndexPath, userInfo: [AnyHashable: Any]? = nil) -> Any? {
return actions[action.key]?.flatMap({ $0.invokeActionOn(cell: cell, item: item, path: path, userInfo: userInfo) }).last
}
open func hasAction(_ action: TableRowActionType) -> Bool {
open func has(action: TableRowActionType) -> Bool {
return actions[action.key] != nil
}
open func isEditingAllowed(forIndexPath indexPath: IndexPath) -> Bool {
if actions[TableRowActionType.canEdit.key] != nil {
return invoke(.canEdit, cell: nil, path: indexPath) as? Bool ?? false
return invoke(action: .canEdit, cell: nil, path: indexPath) as? Bool ?? false
}
return editingActions?.isEmpty == false || actions[TableRowActionType.clickDelete.key] != nil
}
@ -108,16 +83,49 @@ open class TableRow<CellType: ConfigurableCell>: Row where CellType: UITableView
// MARK: - actions -
@discardableResult
open func action(_ action: TableRowAction<CellType>) -> Self {
open func on(_ action: TableRowAction<CellType>) -> Self {
if actions[action.type.key] == nil {
actions[action.type.key] = [TableRowAction<CellType>]()
}
actions[action.type.key]?.append(action)
actions[action.type.key] = action
return self
}
@discardableResult
open func on<T>(_ type: TableRowActionType, handler: @escaping (_ options: TableRowActionOptions<CellType>) -> T) -> Self {
return on(TableRowAction<CellType>(type, handler: handler))
}
open func removeAllActions() {
actions.removeAll()
}
open func removeAction(forActionId actionId: String) {
for (key, value) in actions {
if let actionIndex = value.index(where: { $0.id == actionId }) {
actions[key]?.remove(at: actionIndex)
}
}
}
// MARK: - deprecated actions -
@available(*, deprecated, message: "Use 'on' method instead")
@discardableResult
open func action<T>(_ type: TableRowActionType, handler: @escaping (_ data: TableRowActionData<CellType>) -> T) -> Self {
open func action(_ action: TableRowAction<CellType>) -> Self {
return on(action)
}
@available(*, deprecated, message: "Use 'on' method instead")
@discardableResult
open func action<T>(_ type: TableRowActionType, handler: @escaping (_ options: TableRowActionOptions<CellType>) -> T) -> Self {
actions[type.key] = TableRowAction<CellType>(type, handler: handler)
return self
return on(TableRowAction<CellType>(type, handler: handler))
}
}

View File

@ -20,32 +20,7 @@
import UIKit
public enum TableRowActionType {
case click
case clickDelete
case select
case deselect
case willSelect
case willDisplay
case shouldHighlight
case height
case canEdit
case configure
case custom(String)
var key: String {
switch (self) {
case .custom(let key):
return key
default:
return "_\(self)"
}
}
}
open class TableRowActionData<CellType: ConfigurableCell> where CellType: UITableViewCell {
open class TableRowActionOptions<CellType: ConfigurableCell> where CellType: UITableViewCell {
open let item: CellType.T
open let cell: CellType?
@ -63,38 +38,48 @@ open class TableRowActionData<CellType: ConfigurableCell> where CellType: UITabl
private enum TableRowActionHandler<CellType: ConfigurableCell> where CellType: UITableViewCell {
case voidAction((TableRowActionData<CellType>) -> Void)
case action((TableRowActionData<CellType>) -> Any?)
case voidAction((TableRowActionOptions<CellType>) -> Void)
case action((TableRowActionOptions<CellType>) -> Any?)
func invoke(item: CellType.T, cell: UITableViewCell?, path: IndexPath) -> Any? {
func invoke(withOptions options: TableRowActionOptions<CellType>) -> Any? {
switch self {
case .voidAction(let handler):
return handler(TableRowActionData(item: item, cell: cell as? CellType, path: path, userInfo: nil))
handler(options)
return nil
case .action(let handler):
return handler(TableRowActionData(item: item, cell: cell as? CellType, path: path, userInfo: nil))
return handler(options)
}
}
}
open class TableRowAction<CellType: ConfigurableCell> where CellType: UITableViewCell {
open var id: String?
open let type: TableRowActionType
private let handler: TableRowActionHandler<CellType>
public init(_ type: TableRowActionType, handler: @escaping (_ data: TableRowActionData<CellType>) -> Void) {
public init(_ type: TableRowActionType, handler: @escaping (_ options: TableRowActionOptions<CellType>) -> Void) {
self.type = type
self.handler = .voidAction(handler)
}
public init<T>(_ type: TableRowActionType, handler: @escaping (_ data: TableRowActionData<CellType>) -> T) {
public init(_ key: String, handler: @escaping (_ options: TableRowActionOptions<CellType>) -> Void) {
self.type = .custom(key)
self.handler = .voidAction(handler)
}
public init<T>(_ type: TableRowActionType, handler: @escaping (_ options: TableRowActionOptions<CellType>) -> T) {
self.type = type
self.handler = .action(handler)
}
func invoke(item: CellType.T, cell: UITableViewCell?, path: IndexPath) -> Any? {
return handler.invoke(item: item, cell: cell, path: path)
public func invokeActionOn(cell: UITableViewCell?, item: Any, path: IndexPath, userInfo: [AnyHashable: Any]?) -> Any? {
guard let item = item as? CellType.T else { return nil }
return handler.invoke(withOptions: TableRowActionOptions(item: item, cell: cell as? CellType, path: path, userInfo: userInfo))
}
}

View File

@ -88,6 +88,13 @@ open class TableSection {
rows[index] = row
}
open func delete(rowAt index: Int) {
rows.remove(at: index)
}
// MARK: - deprecated methods -
@available(*, deprecated, message: "Use 'delete(rowAt:)' method instead")
open func delete(index: Int) {
rows.remove(at: index)
}

View File

@ -2,7 +2,7 @@ Pod::Spec.new do |s|
s.name = 'TableKit'
s.module_name = 'TableKit'
s.version = '2.0.0'
s.version = '2.1.0'
s.homepage = 'https://github.com/maxsokolov/TableKit'
s.summary = 'Type-safe declarative table views with Swift.'

View File

@ -8,8 +8,9 @@
/* Begin PBXBuildFile section */
50CF6E6B1D6704FE004746FF /* TableCellRegisterer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50CF6E6A1D6704FE004746FF /* TableCellRegisterer.swift */; };
50E858581DB153F500A9AA55 /* TableKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50E858571DB153F500A9AA55 /* TableKit.swift */; };
DA9EA7AF1D0EC2C90021F650 /* ConfigurableCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA9EA7A61D0EC2C90021F650 /* ConfigurableCell.swift */; };
DA9EA7B01D0EC2C90021F650 /* HeightStrategy.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA9EA7A71D0EC2C90021F650 /* HeightStrategy.swift */; };
DA9EA7B01D0EC2C90021F650 /* TablePrototypeCellHeightCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA9EA7A71D0EC2C90021F650 /* TablePrototypeCellHeightCalculator.swift */; };
DA9EA7B11D0EC2C90021F650 /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA9EA7A81D0EC2C90021F650 /* Operators.swift */; };
DA9EA7B21D0EC2C90021F650 /* TableCellAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA9EA7A91D0EC2C90021F650 /* TableCellAction.swift */; };
DA9EA7B31D0EC2C90021F650 /* TableDirector.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA9EA7AA1D0EC2C90021F650 /* TableDirector.swift */; };
@ -32,9 +33,10 @@
/* Begin PBXFileReference section */
50CF6E6A1D6704FE004746FF /* TableCellRegisterer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableCellRegisterer.swift; sourceTree = "<group>"; };
50E858571DB153F500A9AA55 /* TableKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableKit.swift; sourceTree = "<group>"; };
DA9EA7561D0B679A0021F650 /* TableKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = TableKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
DA9EA7A61D0EC2C90021F650 /* ConfigurableCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConfigurableCell.swift; sourceTree = "<group>"; };
DA9EA7A71D0EC2C90021F650 /* HeightStrategy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeightStrategy.swift; sourceTree = "<group>"; };
DA9EA7A71D0EC2C90021F650 /* TablePrototypeCellHeightCalculator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TablePrototypeCellHeightCalculator.swift; sourceTree = "<group>"; };
DA9EA7A81D0EC2C90021F650 /* Operators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Operators.swift; sourceTree = "<group>"; };
DA9EA7A91D0EC2C90021F650 /* TableCellAction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableCellAction.swift; sourceTree = "<group>"; };
DA9EA7AA1D0EC2C90021F650 /* TableDirector.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableDirector.swift; sourceTree = "<group>"; };
@ -88,15 +90,16 @@
DA9EA7A51D0EC2B90021F650 /* Sources */ = {
isa = PBXGroup;
children = (
50E858571DB153F500A9AA55 /* TableKit.swift */,
DA9EA7AA1D0EC2C90021F650 /* TableDirector.swift */,
50CF6E6A1D6704FE004746FF /* TableCellRegisterer.swift */,
DA9EA7AB1D0EC2C90021F650 /* TableRow.swift */,
DA9EA7AC1D0EC2C90021F650 /* TableRowAction.swift */,
DA9EA7AE1D0EC2C90021F650 /* TableSection.swift */,
DA9EA7A91D0EC2C90021F650 /* TableCellAction.swift */,
DA9EA7A71D0EC2C90021F650 /* TablePrototypeCellHeightCalculator.swift */,
DA9EA7A61D0EC2C90021F650 /* ConfigurableCell.swift */,
DA9EA7A81D0EC2C90021F650 /* Operators.swift */,
DA9EA7A71D0EC2C90021F650 /* HeightStrategy.swift */,
);
path = Sources;
sourceTree = "<group>";
@ -231,11 +234,12 @@
DA9EA7AF1D0EC2C90021F650 /* ConfigurableCell.swift in Sources */,
DA9EA7B31D0EC2C90021F650 /* TableDirector.swift in Sources */,
DA9EA7B71D0EC2C90021F650 /* TableSection.swift in Sources */,
DA9EA7B01D0EC2C90021F650 /* HeightStrategy.swift in Sources */,
DA9EA7B01D0EC2C90021F650 /* TablePrototypeCellHeightCalculator.swift in Sources */,
DA9EA7B51D0EC2C90021F650 /* TableRowAction.swift in Sources */,
DA9EA7B21D0EC2C90021F650 /* TableCellAction.swift in Sources */,
DA9EA7B11D0EC2C90021F650 /* Operators.swift in Sources */,
DA9EA7B41D0EC2C90021F650 /* TableRow.swift in Sources */,
50E858581DB153F500A9AA55 /* TableKit.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@ -171,7 +171,7 @@ class TabletTests: XCTestCase {
let expectation = self.expectation(description: "cell action")
let row = TableRow<TestTableViewCell>(item: TestData(title: "title"))
.action(TableRowAction(.custom(TestTableViewCellOptions.CellAction)) { (data) in
.on(TableRowAction(.custom(TestTableViewCellOptions.CellAction)) { (data) in
XCTAssertNotNil(data.cell, "Action data should have a cell")