rethink point

This commit is contained in:
Max Sokolov 2016-06-09 01:20:52 +03:00
parent 44c1a861d8
commit 234e0efc85
10 changed files with 80 additions and 222 deletions

View File

@ -20,10 +20,6 @@
import UIKit
/**
If you want to delegate your cell configuration logic to cell itself (with your view model or even model) than
just provide an implementation of this protocol for your cell. Enjoy safe-typisation.
*/
public protocol ConfigurableCell {
associatedtype T

View File

@ -19,7 +19,7 @@
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// -
public func +=(left: TableDirector, right: RowBuilder) {
/*public func +=(left: TableDirector, right: RowBuilder) {
left.append(section: TableSectionBuilder(rows: [right]))
}
@ -51,4 +51,4 @@ public func +=(left: TableSectionBuilder, right: RowBuilder) {
public func +=(left: TableSectionBuilder, right: [RowBuilder]) {
left.append(rows: right)
}
}*/

View File

@ -27,7 +27,7 @@ public class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate
public private(set) weak var tableView: UITableView?
private weak var scrollDelegate: UIScrollViewDelegate?
private var sections = [TableSectionBuilder]()
public private(set) var sections = [TableSection]()
public init(tableView: UITableView, scrollDelegate: UIScrollViewDelegate? = nil) {
super.init()
@ -47,24 +47,12 @@ public class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate
public func reload() {
tableView?.reloadData()
}
public func performBatchUpdates(handler: () -> Void) {
}
// MARK: Private methods
private func builderAtIndexPath(indexPath: NSIndexPath) -> (RowBuilder, Int) {
return sections[indexPath.section].builderAtIndex(indexPath.row)!
}
// MARK: Public
public func invoke(action action: ActionType, cell: UITableViewCell?, indexPath: NSIndexPath) -> AnyObject? {
let builder = builderAtIndexPath(indexPath)
return builder.0.invoke(action: action, cell: cell, indexPath: indexPath, itemIndex: builder.1, userInfo: nil)
return nil
}
public override func respondsToSelector(selector: Selector) -> Bool {
@ -81,21 +69,20 @@ public class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate
if let action = notification.object as? Action, indexPath = tableView?.indexPathForCell(action.cell) {
let builder = builderAtIndexPath(indexPath)
builder.0.invoke(action: .custom(action.key), cell: action.cell, indexPath: indexPath, itemIndex: builder.1, userInfo: notification.userInfo)
//let builder = builderAtIndexPath(indexPath)
//builder.0.invoke(action: .custom(action.key), cell: action.cell, indexPath: indexPath, itemIndex: builder.1, userInfo: notification.userInfo)
}
}
// MARK: - Height
public func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
let builder = builderAtIndexPath(indexPath)
return builder.0.estimatedRowHeight(builder.1, indexPath: indexPath)
return sections[indexPath.section].items[indexPath.row].estimatedHeight
}
public func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
let builder = builderAtIndexPath(indexPath)
return builder.0.rowHeight(builder.1, indexPath: indexPath)
return UITableViewAutomaticDimension
}
// MARK: UITableViewDataSource - configuration
@ -109,17 +96,17 @@ public class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate
}
public func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let builder = builderAtIndexPath(indexPath)
let cell = tableView.dequeueReusableCellWithIdentifier(builder.0.reusableIdentifier(builder.1), forIndexPath: indexPath)
let row = sections[indexPath.section].items[indexPath.row]
let cell = tableView.dequeueReusableCellWithIdentifier(row.reusableIdentifier, forIndexPath: indexPath)
if cell.frame.size.width != tableView.frame.size.width {
cell.frame = CGRectMake(0, 0, tableView.frame.size.width, cell.frame.size.height)
cell.layoutIfNeeded()
}
builder.0.configure(cell, path: indexPath, index: builder.1)
row.configure(cell)
return cell
}
@ -184,11 +171,11 @@ public class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate
// MARK: - Sections manipulation -
public func append(section section: TableSectionBuilder) {
public func append(section section: TableSection) {
append(sections: [section])
}
public func append(sections sections: [TableSectionBuilder]) {
public func append(sections sections: [TableSection]) {
sections.forEach { $0.tableDirector = self }
self.sections.appendContentsOf(sections)

View File

@ -1,100 +0,0 @@
//
// 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
public protocol RowItemable {
var reusableIdentifier: String { get }
var estimatedHeight: CGFloat { get }
func configure(cell: UITableViewCell)
}
public class RowItem<DataType, CellType: ConfigurableCell where CellType.T == DataType, CellType: UITableViewCell>: RowItemable {
public let item: DataType
public var reusableIdentifier: String {
return CellType.reusableIdentifier()
}
public var estimatedHeight: CGFloat {
return CellType.estimatedHeight()
}
public init(item: DataType) {
self.item = item
}
public func configure(cell: UITableViewCell) {
(cell as? CellType)?.configure(item)
}
}
public class TableDynamicRowBuilder: RowBuilder {
public private(set) weak var tableDirector: TableDirector?
private var items = [RowItemable]()
public init(items: [RowItemable]) {
self.items = items
}
// MARK: - RowConfigurable -
public func configure(cell: UITableViewCell, path: NSIndexPath, index: Int) {
items[index].configure(cell)
}
// MARK: - RowBuilder -
public var numberOfRows: Int {
return items.count
}
public func reusableIdentifier(index: Int) -> String {
return items[index].reusableIdentifier
}
public func willUpdateDirector(director: TableDirector?) {
}
public func invoke(action action: ActionType, cell: UITableViewCell?, indexPath: NSIndexPath, itemIndex: Int, userInfo: [NSObject : AnyObject]?) -> AnyObject? {
return nil
}
public func action(handler: (item: RowItemable, path: NSIndexPath) -> Void) -> Self {
return self
}
// MARK: - RowHeightCalculatable -
public func rowHeight(index: Int, indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
public func estimatedRowHeight(index: Int, indexPath: NSIndexPath) -> CGFloat {
return items[index].estimatedHeight
}
}

View File

@ -20,26 +20,31 @@
import UIKit
public protocol RowHeightCalculatable {
func rowHeight(index: Int, indexPath: NSIndexPath) -> CGFloat
func estimatedRowHeight(index: Int, indexPath: NSIndexPath) -> CGFloat
public protocol Row {
var reusableIdentifier: String { get }
var estimatedHeight: CGFloat { get }
func configure(cell: UITableViewCell)
}
public protocol RowConfigurable {
public class TableRow<ItemType, CellType: ConfigurableCell where CellType.T == ItemType, CellType: UITableViewCell>: Row {
public let item: ItemType
func configure(cell: UITableViewCell, path: NSIndexPath, index: Int)
}
public protocol RowBuilder: RowConfigurable, RowHeightCalculatable {
public var reusableIdentifier: String {
return CellType.reusableIdentifier()
}
var tableDirector: TableDirector? { get }
var numberOfRows: Int { get }
public var estimatedHeight: CGFloat {
return CellType.estimatedHeight()
}
func willUpdateDirector(director: TableDirector?)
public init(item: ItemType) {
self.item = item
}
func reusableIdentifier(index: Int) -> String
func invoke(action action: ActionType, cell: UITableViewCell?, indexPath: NSIndexPath, itemIndex: Int, userInfo: [NSObject: AnyObject]?) -> AnyObject?
public func configure(cell: UITableViewCell) {
(cell as? CellType)?.configure(item)
}
}

View File

@ -25,7 +25,7 @@ public typealias ReturnValue = AnyObject?
/**
Responsible for building cells of given type and passing items to them.
*/
public class TableRowBuilder<DataType, CellType: ConfigurableCell where CellType.T == DataType, CellType: UITableViewCell> : RowBuilder {
/*public class TableRowBuilder<DataType, CellType: ConfigurableCell where CellType.T == DataType, CellType: UITableViewCell> : RowBuilder {
public private(set) weak var tableDirector: TableDirector?
private var heightStrategy: HeightStrategy?
@ -165,4 +165,4 @@ public class TableRowBuilder<DataType, CellType: ConfigurableCell where CellType
public func clear() {
items.removeAll()
}
}
}*/

View File

@ -24,16 +24,17 @@ import UIKit
Responsible for building a certain table view section.
Can host several row builders.
*/
public class TableSectionBuilder {
public class TableSection {
weak var tableDirector: TableDirector? {
didSet {
guard let director = tableDirector else { return }
builders.forEach { $0.willUpdateDirector(director) }
//guard let director = tableDirector else { return }
//builders.forEach { $0.willUpdateDirector(director) }
}
}
private var builders = [RowBuilder]()
public private(set) var items = [Row]()
public var headerTitle: String?
public var footerTitle: String?
@ -43,24 +44,24 @@ public class TableSectionBuilder {
/// A total number of rows in section of each row builder.
public var numberOfRowsInSection: Int {
return builders.reduce(0) { $0 + $1.numberOfRows }
return items.count
}
public init(rows: [RowBuilder]? = nil) {
public init(rows: [Row]? = nil) {
if let initialRows = rows {
builders.appendContentsOf(initialRows)
items.appendContentsOf(initialRows)
}
}
public convenience init(headerTitle: String?, footerTitle: String?, rows: [RowBuilder]?) {
public convenience init(headerTitle: String?, footerTitle: String?, rows: [Row]?) {
self.init(rows: rows)
self.headerTitle = headerTitle
self.footerTitle = footerTitle
}
public convenience init(headerView: UIView?, footerView: UIView?, rows: [RowBuilder]?) {
public convenience init(headerView: UIView?, footerView: UIView?, rows: [Row]?) {
self.init(rows: rows)
self.headerView = headerView
@ -70,31 +71,16 @@ public class TableSectionBuilder {
// MARK: - Public -
public func clear() {
builders.removeAll()
items.removeAll()
}
public func append(row row: RowBuilder) {
public func append(row row: Row) {
append(rows: [row])
}
public func append(rows rows: [RowBuilder]) {
public func append(rows rows: [Row]) {
if let director = tableDirector { rows.forEach { $0.willUpdateDirector(director) } }
builders.appendContentsOf(rows)
}
// MARK: - Internal -
func builderAtIndex(index: Int) -> (RowBuilder, Int)? {
var builderIndex = index
for builder in builders {
if builderIndex < builder.numberOfRows {
return (builder, builderIndex)
}
builderIndex -= builder.numberOfRows
}
return nil
//if let director = tableDirector { rows.forEach { $0.willUpdateDirector(director) } }
//builders.appendContentsOf(rows)
}
}

View File

@ -8,15 +8,14 @@
/* Begin PBXBuildFile section */
DA08A04F1CF3AB0C00BBF1F8 /* ConfigurableCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA08A04E1CF3AB0C00BBF1F8 /* ConfigurableCell.swift */; };
DA08A0511CF3AB6100BBF1F8 /* RowBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA08A0501CF3AB6100BBF1F8 /* RowBuilder.swift */; };
DA539C9F1CFB025C00368ACB /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA539C9E1CFB025C00368ACB /* Operators.swift */; };
DA539CC61D01D44500368ACB /* TableDynamicRowBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA539CC51D01D44500368ACB /* TableDynamicRowBuilder.swift */; };
DA539CC61D01D44500368ACB /* TableRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA539CC51D01D44500368ACB /* TableRow.swift */; };
DA9EA7351D06155E0021F650 /* HeightStrategy.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA9EA7341D06155E0021F650 /* HeightStrategy.swift */; };
DAC2D6741C9D743D009E9C19 /* Tablet.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC2D6691C9D743D009E9C19 /* Tablet.framework */; };
DAC2D6871C9D7517009E9C19 /* Tablet.h in Headers */ = {isa = PBXBuildFile; fileRef = DAC2D6851C9D7517009E9C19 /* Tablet.h */; settings = {ATTRIBUTES = (Public, ); }; };
DAC2D6901C9D799E009E9C19 /* TableDirector.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAC2D68C1C9D799E009E9C19 /* TableDirector.swift */; };
DAC2D6911C9D799E009E9C19 /* TableRowBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAC2D68D1C9D799E009E9C19 /* TableRowBuilder.swift */; };
DAC2D6921C9D799E009E9C19 /* TableSectionBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAC2D68E1C9D799E009E9C19 /* TableSectionBuilder.swift */; };
DAC2D6921C9D799E009E9C19 /* TableSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAC2D68E1C9D799E009E9C19 /* TableSection.swift */; };
DAC2D6931C9D799E009E9C19 /* Tablet.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAC2D68F1C9D799E009E9C19 /* Tablet.swift */; };
DAC2D6991C9D7A3F009E9C19 /* TabletTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAC2D6961C9D7A3B009E9C19 /* TabletTests.swift */; };
/* End PBXBuildFile section */
@ -33,9 +32,8 @@
/* Begin PBXFileReference section */
DA08A04E1CF3AB0C00BBF1F8 /* ConfigurableCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConfigurableCell.swift; sourceTree = "<group>"; };
DA08A0501CF3AB6100BBF1F8 /* RowBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RowBuilder.swift; sourceTree = "<group>"; };
DA539C9E1CFB025C00368ACB /* Operators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Operators.swift; sourceTree = "<group>"; };
DA539CC51D01D44500368ACB /* TableDynamicRowBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableDynamicRowBuilder.swift; sourceTree = "<group>"; };
DA539CC51D01D44500368ACB /* TableRow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableRow.swift; sourceTree = "<group>"; };
DA9EA7341D06155E0021F650 /* HeightStrategy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeightStrategy.swift; sourceTree = "<group>"; };
DAC2D6691C9D743D009E9C19 /* Tablet.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Tablet.framework; sourceTree = BUILT_PRODUCTS_DIR; };
DAC2D6731C9D743D009E9C19 /* TabletTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TabletTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
@ -43,7 +41,7 @@
DAC2D6851C9D7517009E9C19 /* Tablet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Tablet.h; sourceTree = "<group>"; };
DAC2D68C1C9D799E009E9C19 /* TableDirector.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableDirector.swift; sourceTree = "<group>"; };
DAC2D68D1C9D799E009E9C19 /* TableRowBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableRowBuilder.swift; sourceTree = "<group>"; };
DAC2D68E1C9D799E009E9C19 /* TableSectionBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableSectionBuilder.swift; sourceTree = "<group>"; };
DAC2D68E1C9D799E009E9C19 /* TableSection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableSection.swift; sourceTree = "<group>"; };
DAC2D68F1C9D799E009E9C19 /* Tablet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Tablet.swift; sourceTree = "<group>"; };
DAC2D6951C9D7A3B009E9C19 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
DAC2D6961C9D7A3B009E9C19 /* TabletTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TabletTests.swift; sourceTree = "<group>"; };
@ -100,11 +98,10 @@
isa = PBXGroup;
children = (
DAC2D68C1C9D799E009E9C19 /* TableDirector.swift */,
DA08A0501CF3AB6100BBF1F8 /* RowBuilder.swift */,
DA9EA7341D06155E0021F650 /* HeightStrategy.swift */,
DA539CC51D01D44500368ACB /* TableRow.swift */,
DAC2D68E1C9D799E009E9C19 /* TableSection.swift */,
DAC2D68D1C9D799E009E9C19 /* TableRowBuilder.swift */,
DA539CC51D01D44500368ACB /* TableDynamicRowBuilder.swift */,
DAC2D68E1C9D799E009E9C19 /* TableSectionBuilder.swift */,
DA9EA7341D06155E0021F650 /* HeightStrategy.swift */,
DA08A04E1CF3AB0C00BBF1F8 /* ConfigurableCell.swift */,
DAC2D68F1C9D799E009E9C19 /* Tablet.swift */,
DA539C9E1CFB025C00368ACB /* Operators.swift */,
@ -231,10 +228,9 @@
buildActionMask = 2147483647;
files = (
DAC2D6901C9D799E009E9C19 /* TableDirector.swift in Sources */,
DAC2D6921C9D799E009E9C19 /* TableSectionBuilder.swift in Sources */,
DAC2D6921C9D799E009E9C19 /* TableSection.swift in Sources */,
DA9EA7351D06155E0021F650 /* HeightStrategy.swift in Sources */,
DA08A0511CF3AB6100BBF1F8 /* RowBuilder.swift in Sources */,
DA539CC61D01D44500368ACB /* TableDynamicRowBuilder.swift in Sources */,
DA539CC61D01D44500368ACB /* TableRow.swift in Sources */,
DA08A04F1CF3AB0C00BBF1F8 /* ConfigurableCell.swift in Sources */,
DAC2D6911C9D799E009E9C19 /* TableRowBuilder.swift in Sources */,
DAC2D6931C9D799E009E9C19 /* Tablet.swift in Sources */,

View File

@ -21,13 +21,13 @@ class HeaderFooterController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let rows = TableRowBuilder<String, StoryboardTableViewCell>(items: ["3", "4", "5"])
//let rows = TableRowBuilder<String, StoryboardTableViewCell>(items: ["3", "4", "5"])
let headerView = UIView(frame: CGRectMake(0, 0, 100, 100))
headerView.backgroundColor = UIColor.lightGrayColor()
//let headerView = UIView(frame: CGRectMake(0, 0, 100, 100))
//headerView.backgroundColor = UIColor.lightGrayColor()
let section = TableSectionBuilder(headerView: headerView, footerView: nil, rows: [rows])
//let section = TableSectionBuilder(headerView: headerView, footerView: nil, rows: [rows])
tableDirector += section
//tableDirector += section
}
}

View File

@ -21,44 +21,32 @@ class MainController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let rowBuilder = TableRowBuilder<String, StoryboardImageTableViewCell>(items: ["1", "1", "1", "1"])
/*let rowBuilder = TableRowBuilder<String, StoryboardImageTableViewCell>(items: ["1", "1", "1", "1"])
.action(.click) { [unowned self] data in
self.performSegueWithIdentifier("headerfooter", sender: nil)
}
let section = TableSectionBuilder(headerTitle: "", footerTitle: "", rows: [rowBuilder])
}*/
let cellItem = RowItem<String, StoryboardImageTableViewCell>(item: "1")
let cellItem2 = RowItem<String, StoryboardImageTableViewCell>(item: "2")
let cellItem3 = RowItem<String, StoryboardImageTableViewCell>(item: "3")
let row1 = TableRow<String, StoryboardImageTableViewCell>(item: "1")
let row2 = TableRow<String, StoryboardImageTableViewCell>(item: "2")
let row3 = TableRow<String, StoryboardImageTableViewCell>(item: "3")
let b = TableDynamicRowBuilder(items: [cellItem, cellItem2, cellItem3])
.action { (item, path) in
if let x = item as? RowItem<String, StoryboardImageTableViewCell> {
}
}
.action { (item, path) in
}
let section = TableSection(headerTitle: "", footerTitle: "", rows: [row1, row2, row3])
tableDirector += b
tableDirector.append(section: section)