ActionHandler approach

This commit is contained in:
Max Sokolov 2015-11-13 01:00:12 +03:00
parent 9c3a1ee5c9
commit f8c659f069
4 changed files with 58 additions and 74 deletions

View File

@ -21,17 +21,29 @@
import UIKit
import Foundation
internal enum ActionHandler<T, E> {
case actionBlock((data: ActionData<T, E>) -> Void)
case actionReturnBlock((data: ActionData<T, E>) -> AnyObject)
func call(data: ActionData<T, E>) -> AnyObject {
switch (self) {
case .actionBlock(let closure):
closure(data: data)
return true
case .actionReturnBlock(let closure):
return closure(data: data)
}
}
}
/**
Responsible for building cells of given type and passing items to them.
*/
public class TableRowBuilder<I, C where C: UITableViewCell> : RowBuilder {
public typealias ReturnValue = AnyObject
public typealias TableRowBuilderActionBlock = (data: ActionData<I, C>) -> Void
public typealias TableRowBuilderReturnValueActionBlock = (data: ActionData<I, C>) -> ReturnValue
private var actions = Dictionary<String, TableRowBuilderActionBlock>()
private var actions = Dictionary<String, ActionHandler<I, C>>()
private var items = [I]()
public var reusableIdentifier: String
@ -68,35 +80,32 @@ public class TableRowBuilder<I, C where C: UITableViewCell> : RowBuilder {
// MARK: Chaining actions
public func action(key: String, action: TableRowBuilderActionBlock) -> Self {
public func action(key: String, action: (data: ActionData<I, C>) -> Void) -> Self {
actions[key] = action
actions[key] = .actionBlock(action)
return self
}
public func action(key: ActionType, action: TableRowBuilderActionBlock) -> Self {
public func action(key: ActionType, action: (data: ActionData<I, C>) -> Void) -> Self {
actions[key.rawValue] = action
actions[key.rawValue] = .actionBlock(action)
return self
}
public func action(key: ActionType, action: TableRowBuilderReturnValueActionBlock) -> Self {
public func action(key: ActionType, action: (data: ActionData<I, C>) -> AnyObject) -> Self {
actions[key.rawValue] = .actionReturnBlock(action)
return self
}
// MARK: Triggers
public func triggerAction(key: String, cell: UITableViewCell, indexPath: NSIndexPath, itemIndex: Int) -> ActionResult {
public func triggerAction(key: String, cell: UITableViewCell?, indexPath: NSIndexPath, itemIndex: Int) -> AnyObject? {
let actionData = ActionData(cell: cell as! C, indexPath: indexPath, item: items[itemIndex], itemIndex: itemIndex)
if let block = actions[key] {
block(data: actionData)
return .Failure
if let action = actions[key] {
return action.call(ActionData(cell: cell as? C, indexPath: indexPath, item: items[itemIndex], itemIndex: itemIndex))
}
return .Failure
return nil
}
}
@ -113,9 +122,9 @@ public class TableConfigurableRowBuilder<I, C: ConfigurableCell where C.Item ==
super.init(items: items, id: C.reusableIdentifier())
}
public override func triggerAction(key: String, cell: UITableViewCell, indexPath: NSIndexPath, itemIndex: Int) -> ActionResult {
public override func triggerAction(key: String, cell: UITableViewCell?, indexPath: NSIndexPath, itemIndex: Int) -> AnyObject? {
(cell as! C).configureWithItem(items[itemIndex])
(cell as? C)?.configureWithItem(items[itemIndex])
return super.triggerAction(key, cell: cell, indexPath: indexPath, itemIndex: itemIndex)
}

View File

@ -39,12 +39,12 @@ public enum ActionType : String {
public struct ActionData<I, C> {
public let cell: C
public let cell: C?
public let item: I
public let itemIndex: Int
public let indexPath: NSIndexPath
init(cell: C, indexPath: NSIndexPath, item: I, itemIndex: Int) {
init(cell: C?, indexPath: NSIndexPath, item: I, itemIndex: Int) {
self.cell = cell
self.indexPath = indexPath
@ -53,31 +53,6 @@ public struct ActionData<I, C> {
}
}
public enum ActionResult {
case Success(returnValue: AnyObject)
case Failure
/// Returns true if the result is a success, false otherwise.
public var isSuccess: Bool {
switch self {
case .Success:
return true
case .Failure:
return false
}
}
public var returnValue: AnyObject? {
switch self {
case .Success(let returnValue):
return returnValue
case .Failure:
return nil
}
}
}
/**
A custom action that you can trigger from your cell.
You can eacily catch actions using a chaining manner with your row builder.
@ -127,10 +102,9 @@ public protocol RowBuilder {
var numberOfRows: Int { get }
var reusableIdentifier: String { get }
func triggerAction(key: String, cell: UITableViewCell, indexPath: NSIndexPath, itemIndex: Int) -> ActionResult
func triggerAction(key: String, cell: UITableViewCell?, indexPath: NSIndexPath, itemIndex: Int) -> AnyObject?
}
/**
Responsible for table view's datasource and delegate.
*/
@ -179,15 +153,10 @@ public class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate
return sections[indexPath.section].builderAtIndex(indexPath.row)!
}
private func triggerAction(action: ActionType, cell: UITableViewCell?, indexPath: NSIndexPath) -> ActionResult {
private func triggerAction(action: ActionType, cell: UITableViewCell?, indexPath: NSIndexPath) -> AnyObject? {
let builder = builderAtIndexPath(indexPath)
return builder.0.triggerAction(action.rawValue, cell: cell!, indexPath: indexPath, itemIndex: builder.1)
}
private func trigger() -> AnyObject {
return 100
return builder.0.triggerAction(action.rawValue, cell: cell, indexPath: indexPath, itemIndex: builder.1)
}
internal func didReceiveAction(notification: NSNotification) {
@ -262,7 +231,7 @@ public class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate
let cell = tableView.cellForRowAtIndexPath(indexPath)
if triggerAction(.click, cell: cell, indexPath: indexPath).isSuccess {
if triggerAction(.click, cell: cell, indexPath: indexPath) != nil {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
} else {
triggerAction(.select, cell: cell, indexPath: indexPath)
@ -281,11 +250,11 @@ public class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate
public func tableView(tableView: UITableView, shouldHighlightRowAtIndexPath indexPath: NSIndexPath) -> Bool {
return triggerAction(.shouldHighlight, cell: tableView.cellForRowAtIndexPath(indexPath), indexPath: indexPath).returnValue as? Bool ?? true
return triggerAction(.shouldHighlight, cell: tableView.cellForRowAtIndexPath(indexPath), indexPath: indexPath) as? Bool ?? true
}
public func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return triggerAction(.height, cell: tableView.cellForRowAtIndexPath(indexPath), indexPath: indexPath).returnValue as? CGFloat ?? tableView.rowHeight
return triggerAction(.height, cell: nil, indexPath: indexPath) as? CGFloat ?? tableView.rowHeight
}
}

View File

@ -19,21 +19,27 @@ class ViewController: UIViewController {
tableDirector = TableDirector(tableView: tableView)
let rowBuilder = TableRowBuilder<Int, UITableViewCell>(items: [1, 2, 3, 4], id: "cell")
.action(.configure) { data in
.action(.configure) { data -> Void in
data.cell.textLabel?.text = "\(data.item)"
data.cell?.textLabel?.text = "\(data.item)"
}
.action(.shouldHighlight) { _ in
.action(.height) { data in
return 50
}
.action(.shouldHighlight) { data in
return false
}
let configurableRowBuilder = TableConfigurableRowBuilder<String, ConfigurableTableViewCell>(items: ["5", "6", "7", "8"])
.action(kConfigurableTableViewCellButtonClickedAction) { data in
.action(kConfigurableTableViewCellButtonClickedAction) { data -> Void in
print("custom action indexPath: \(data.indexPath), item: \(data.item)")
}
.action(.click) { data in
.action(.click) { data -> Void in
data.cell!.textLabel?.text = ""
print("custom action indexPath: \(data.indexPath), item: \(data.item)")
}