From 051dba0e970e017ab74d419a738b760ef3b79338 Mon Sep 17 00:00:00 2001 From: Max Sokolov Date: Wed, 25 May 2016 21:54:04 +0300 Subject: [PATCH] builders to separate files --- .../UserInterfaceState.xcuserstate | Bin 18832 -> 18062 bytes Tablet/TableBaseRowBuilder.swift | 135 ++++++++++++ Tablet/TablePrototypeRowBuilder.swift | 112 ++++++++++ Tablet/TableRowBuilder.swift | 208 +----------------- Tablet/Tablet.xcodeproj/project.pbxproj | 16 +- 5 files changed, 263 insertions(+), 208 deletions(-) create mode 100644 Tablet/TableBaseRowBuilder.swift create mode 100644 Tablet/TablePrototypeRowBuilder.swift diff --git a/Tablet.xcworkspace/xcuserdata/max.xcuserdatad/UserInterfaceState.xcuserstate b/Tablet.xcworkspace/xcuserdata/max.xcuserdatad/UserInterfaceState.xcuserstate index bb497d2bd25cc669c22a1cf2a053676b4919f68c..b016cadf59844c2010e0917ab4e8bf123f58a10b 100644 GIT binary patch delta 6954 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 delta 7624 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 : RowBuilder { + + public private(set) weak var tableDirector: TableDirector? + + private var actions = [String: ActionHandler]() + private var items = [DataType]() + + public let reusableIdentifier: String + + public var numberOfRows: Int { + return items.count + } + + public init(item: DataType, id: String? = nil) { + + reusableIdentifier = id ?? String(CellType) + items.append(item) + } + + public init(items: [DataType]? = nil, id: String? = nil) { + + reusableIdentifier = id ?? String(CellType) + + if let items = items { + self.items.appendContentsOf(items) + } + } + + public func rowHeight(index: Int) -> CGFloat { + return UITableViewAutomaticDimension + } + + public func estimatedRowHeight() -> CGFloat { + return 44 + } + + // MARK: - Chaining actions - + + public func action(key: String, handler: (data: ActionData) -> Void) -> Self { + + actions[key] = .Handler(handler) + return self + } + + public func action(type: ActionType, handler: (data: ActionData) -> Void) -> Self { + + actions[type.key] = .Handler(handler) + return self + } + + public func valueAction(type: ActionType, handler: (data: ActionData) -> ReturnValue) -> Self { + + actions[type.key] = .ValueHandler(handler) + return self + } + + public func invoke(action action: ActionType, cell: UITableViewCell?, indexPath: NSIndexPath, itemIndex: Int, userInfo: [NSObject: AnyObject]?) -> AnyObject? { + + if let action = actions[action.key] { + return action.invoke(ActionData(cell: cell as? CellType, indexPath: indexPath, item: items[itemIndex], itemIndex: itemIndex, userInfo: userInfo)) + } + return nil + } + + private func registerCell(inTableView tableView: UITableView) { + + if tableView.dequeueReusableCellWithIdentifier(reusableIdentifier) != nil { + return + } + + let resource = String(CellType) + let bundle = NSBundle(forClass: CellType.self) + + if let _ = bundle.pathForResource(resource, ofType: "nib") { // existing cell + tableView.registerNib(UINib(nibName: resource, bundle: bundle), forCellReuseIdentifier: reusableIdentifier) + } else { + tableView.registerClass(CellType.self, forCellReuseIdentifier: reusableIdentifier) + } + } + + public func willUpdateDirector(director: TableDirector?) { + tableDirector = director + + + } + + // MARK: - Items manipulation - + + public func item(index index: Int) -> DataType { + return items[index] + } + + public func append(items items: [DataType]) { + self.items.appendContentsOf(items) + } + + public func clear() { + items.removeAll() + } +} + +public func +=(left: TableBaseRowBuilder, right: DataType) { + left.append(items: [right]) +} + +public func +=(left: TableBaseRowBuilder, right: [DataType]) { + left.append(items: right) +} \ No newline at end of file diff --git a/Tablet/TablePrototypeRowBuilder.swift b/Tablet/TablePrototypeRowBuilder.swift new file mode 100644 index 0000000..b28cf68 --- /dev/null +++ b/Tablet/TablePrototypeRowBuilder.swift @@ -0,0 +1,112 @@ +// +// 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 class TablePrototypeRowBuilder : TableBaseRowBuilder { + + private var cachedHeights = [Int: CGFloat]() + private var prototypeCell: CellType? + + public init(item: DataType) { + super.init(item: item, id: CellType.reusableIdentifier()) + } + + public init(items: [DataType]? = nil) { + super.init(items: items, id: CellType.reusableIdentifier()) + } + + public override func estimatedRowHeight() -> CGFloat { + return UITableViewAutomaticDimension + } + + func heightCall(item: DataType, width: CGFloat) -> CGFloat { + + guard let cell = prototypeCell else { return 0 } + + cell.bounds = CGRectMake(0, 0, width, cell.bounds.height) + + cell.configure(item) + + cell.setNeedsLayout() + cell.layoutIfNeeded() + + return cell.contentView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height + 1 + } + + // прехит по мере скроллинга в бэк + // прехит не должен прехитить то что уже есть (показанное) + // по мере скроллинга уметь отменять перхит () + + public override func rowHeight(index: Int) -> CGFloat { + + guard let cell = prototypeCell else { return 0 } + + let itemz = item(index: index) + + if let height = cachedHeights[itemz.hashValue] { + return height + } + + let height = heightCall(itemz, width: tableDirector?.tableView?.bounds.size.width ?? 0) + + cachedHeights[itemz.hashValue] = height + + print(tableDirector?.tableView?.bounds.size.width, cell.bounds.height, height) + + return height + } + + public func preheat(item: DataType) { + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { + + let height = self.heightCall(item, width: 0) + + // check if actual height exists + // calc height + + //let heights = self.items.map { self.heightZ($0) } + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { + + // check if table width is actual + // store height in cache + } + } + } + + public override func invoke(action action: ActionType, cell: UITableViewCell?, indexPath: NSIndexPath, itemIndex: Int, userInfo: [NSObject: AnyObject]?) -> AnyObject? { + + if case .configure = action { + + (cell as? CellType)?.configure(item(index: itemIndex)) + } + return super.invoke(action: action, cell: cell, indexPath: indexPath, itemIndex: itemIndex, userInfo: userInfo) + } + + public override func willUpdateDirector(director: TableDirector?) { + + //tableDirector = director + if let tableView = director?.tableView, cell = tableView.dequeueReusableCellWithIdentifier(reusableIdentifier) as? CellType { + prototypeCell = cell + } + } +} \ No newline at end of file diff --git a/Tablet/TableRowBuilder.swift b/Tablet/TableRowBuilder.swift index b101ddc..210a3e8 100644 --- a/Tablet/TableRowBuilder.swift +++ b/Tablet/TableRowBuilder.swift @@ -20,108 +20,6 @@ import UIKit -public typealias ReturnValue = AnyObject? - -/** - Responsible for building cells of given type and passing items to them. - */ -public class TableBaseRowBuilder : RowBuilder { - - public private(set) weak var tableDirector: TableDirector? - - private var actions = [String: ActionHandler]() - private var items = [DataType]() - - public let reusableIdentifier: String - - public var numberOfRows: Int { - return items.count - } - - public init(item: DataType, id: String? = nil) { - - reusableIdentifier = id ?? String(CellType) - items.append(item) - } - - public init(items: [DataType]? = nil, id: String? = nil) { - - reusableIdentifier = id ?? String(CellType) - - if let items = items { - self.items.appendContentsOf(items) - } - } - - public func rowHeight(index: Int) -> CGFloat { - return UITableViewAutomaticDimension - } - - public func estimatedRowHeight() -> CGFloat { - return 44 - } - - // MARK: - Chaining actions - - - public func action(key: String, handler: (data: ActionData) -> Void) -> Self { - - actions[key] = .Handler(handler) - return self - } - - public func action(type: ActionType, handler: (data: ActionData) -> Void) -> Self { - - actions[type.key] = .Handler(handler) - return self - } - - public func valueAction(type: ActionType, handler: (data: ActionData) -> ReturnValue) -> Self { - - actions[type.key] = .ValueHandler(handler) - return self - } - - public func invoke(action action: ActionType, cell: UITableViewCell?, indexPath: NSIndexPath, itemIndex: Int, userInfo: [NSObject: AnyObject]?) -> AnyObject? { - - if let action = actions[action.key] { - return action.invoke(ActionData(cell: cell as? CellType, indexPath: indexPath, item: items[itemIndex], itemIndex: itemIndex, userInfo: userInfo)) - } - return nil - } - - private func registerCell(inTableView tableView: UITableView) { - - if tableView.dequeueReusableCellWithIdentifier(reusableIdentifier) != nil { - return - } - - let resource = String(CellType) - let bundle = NSBundle(forClass: CellType.self) - - if let _ = bundle.pathForResource(resource, ofType: "nib") { // existing cell - tableView.registerNib(UINib(nibName: resource, bundle: bundle), forCellReuseIdentifier: reusableIdentifier) - } else { - tableView.registerClass(CellType.self, forCellReuseIdentifier: reusableIdentifier) - } - } - - public func willUpdateDirector(director: TableDirector?) { - tableDirector = director - - - } - - // MARK: - Items manipulation - - - public func append(items items: [DataType]) { - self.items.appendContentsOf(items) - } - - public func clear() { - items.removeAll() - } -} - /** Responsible for building configurable cells of given type and passing items to them. */ @@ -130,118 +28,20 @@ public class TableRowBuilder AnyObject? { if case .configure = action { - (cell as? CellType)?.configure(items[itemIndex]) + (cell as? CellType)?.configure(item(index: itemIndex)) } return super.invoke(action: action, cell: cell, indexPath: indexPath, itemIndex: itemIndex, userInfo: userInfo) } - + public override func estimatedRowHeight() -> CGFloat { return CGFloat(CellType.estimatedHeight()) } -} - -public class TablePrototypeRowBuilder : TableBaseRowBuilder { - - private var cachedHeights = [Int: CGFloat]() - private var prototypeCell: CellType? - - public init(item: DataType) { - super.init(item: item, id: CellType.reusableIdentifier()) - } - - public init(items: [DataType]? = nil) { - super.init(items: items, id: CellType.reusableIdentifier()) - } - - public override func estimatedRowHeight() -> CGFloat { - return UITableViewAutomaticDimension - } - - func heightCall(item: DataType, width: CGFloat) -> CGFloat { - - guard let cell = prototypeCell else { return 0 } - - cell.bounds = CGRectMake(0, 0, width, cell.bounds.height) - - cell.configure(item) - - cell.setNeedsLayout() - cell.layoutIfNeeded() - - return cell.contentView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height + 1 - } - - // прехит по мере скроллинга в бэк - // прехит не должен прехитить то что уже есть (показанное) - // по мере скроллинга уметь отменять перхит () - - public override func rowHeight(index: Int) -> CGFloat { - - guard let cell = prototypeCell else { return 0 } - - let item = items[index] - - if let height = cachedHeights[item.hashValue] { - return height - } - - let height = heightCall(item, width: tableDirector?.tableView?.bounds.size.width ?? 0) - - cachedHeights[item.hashValue] = height - - print(tableDirector?.tableView?.bounds.size.width, cell.bounds.height, height) - - return height - } - - public func preheat(item: DataType) { - - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { - - let height = self.heightCall(item, width: 0) - - // check if actual height exists - // calc height - - //let heights = self.items.map { self.heightZ($0) } - - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { - - // check if table width is actual - // store height in cache - } - } - } - - public override func invoke(action action: ActionType, cell: UITableViewCell?, indexPath: NSIndexPath, itemIndex: Int, userInfo: [NSObject: AnyObject]?) -> AnyObject? { - - if case .configure = action { - (cell as? CellType)?.configure(items[itemIndex]) - } - return super.invoke(action: action, cell: cell, indexPath: indexPath, itemIndex: itemIndex, userInfo: userInfo) - } - - public override func willUpdateDirector(director: TableDirector?) { - - tableDirector = director - if let tableView = director?.tableView, cell = tableView.dequeueReusableCellWithIdentifier(reusableIdentifier) as? CellType { - prototypeCell = cell - } - } -} - -public func +=(left: TableBaseRowBuilder, right: DataType) { - left.append(items: [right]) -} - -public func +=(left: TableBaseRowBuilder, right: [DataType]) { - left.append(items: right) } \ No newline at end of file diff --git a/Tablet/Tablet.xcodeproj/project.pbxproj b/Tablet/Tablet.xcodeproj/project.pbxproj index ed7ad7e..77a0417 100644 --- a/Tablet/Tablet.xcodeproj/project.pbxproj +++ b/Tablet/Tablet.xcodeproj/project.pbxproj @@ -7,12 +7,14 @@ objects = { /* Begin PBXBuildFile section */ + 5058386E1CF62B0700224C58 /* TableRowBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5058386D1CF62B0700224C58 /* TableRowBuilder.swift */; }; + 505838701CF62B1300224C58 /* TablePrototypeRowBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5058386F1CF62B1300224C58 /* TablePrototypeRowBuilder.swift */; }; DA08A04F1CF3AB0C00BBF1F8 /* ConfigurableCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA08A04E1CF3AB0C00BBF1F8 /* ConfigurableCell.swift */; }; DA08A0511CF3AB6100BBF1F8 /* RowBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA08A0501CF3AB6100BBF1F8 /* RowBuilder.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 */; }; + DAC2D6911C9D799E009E9C19 /* TableBaseRowBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAC2D68D1C9D799E009E9C19 /* TableBaseRowBuilder.swift */; }; DAC2D6921C9D799E009E9C19 /* TableSectionBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAC2D68E1C9D799E009E9C19 /* TableSectionBuilder.swift */; }; DAC2D6931C9D799E009E9C19 /* Tablet.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAC2D68F1C9D799E009E9C19 /* Tablet.swift */; }; DAC2D6991C9D7A3F009E9C19 /* TabletTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAC2D6961C9D7A3B009E9C19 /* TabletTests.swift */; }; @@ -29,6 +31,8 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 5058386D1CF62B0700224C58 /* TableRowBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableRowBuilder.swift; sourceTree = ""; }; + 5058386F1CF62B1300224C58 /* TablePrototypeRowBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TablePrototypeRowBuilder.swift; sourceTree = ""; }; DA08A04E1CF3AB0C00BBF1F8 /* ConfigurableCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConfigurableCell.swift; sourceTree = ""; }; DA08A0501CF3AB6100BBF1F8 /* RowBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RowBuilder.swift; sourceTree = ""; }; DAC2D6691C9D743D009E9C19 /* Tablet.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Tablet.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -36,7 +40,7 @@ DAC2D6841C9D7517009E9C19 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; DAC2D6851C9D7517009E9C19 /* Tablet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Tablet.h; sourceTree = ""; }; DAC2D68C1C9D799E009E9C19 /* TableDirector.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableDirector.swift; sourceTree = ""; }; - DAC2D68D1C9D799E009E9C19 /* TableRowBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableRowBuilder.swift; sourceTree = ""; }; + DAC2D68D1C9D799E009E9C19 /* TableBaseRowBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableBaseRowBuilder.swift; sourceTree = ""; }; DAC2D68E1C9D799E009E9C19 /* TableSectionBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableSectionBuilder.swift; sourceTree = ""; }; DAC2D68F1C9D799E009E9C19 /* Tablet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Tablet.swift; sourceTree = ""; }; DAC2D6951C9D7A3B009E9C19 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -96,7 +100,9 @@ DA08A04E1CF3AB0C00BBF1F8 /* ConfigurableCell.swift */, DA08A0501CF3AB6100BBF1F8 /* RowBuilder.swift */, DAC2D68C1C9D799E009E9C19 /* TableDirector.swift */, - DAC2D68D1C9D799E009E9C19 /* TableRowBuilder.swift */, + DAC2D68D1C9D799E009E9C19 /* TableBaseRowBuilder.swift */, + 5058386D1CF62B0700224C58 /* TableRowBuilder.swift */, + 5058386F1CF62B1300224C58 /* TablePrototypeRowBuilder.swift */, DAC2D68E1C9D799E009E9C19 /* TableSectionBuilder.swift */, DAC2D68F1C9D799E009E9C19 /* Tablet.swift */, ); @@ -225,7 +231,9 @@ DAC2D6921C9D799E009E9C19 /* TableSectionBuilder.swift in Sources */, DA08A0511CF3AB6100BBF1F8 /* RowBuilder.swift in Sources */, DA08A04F1CF3AB0C00BBF1F8 /* ConfigurableCell.swift in Sources */, - DAC2D6911C9D799E009E9C19 /* TableRowBuilder.swift in Sources */, + DAC2D6911C9D799E009E9C19 /* TableBaseRowBuilder.swift in Sources */, + 5058386E1CF62B0700224C58 /* TableRowBuilder.swift in Sources */, + 505838701CF62B1300224C58 /* TablePrototypeRowBuilder.swift in Sources */, DAC2D6931C9D799E009E9C19 /* Tablet.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0;