diff --git a/.travis.yml b/.travis.yml index c8bd684..15e483a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ language: objective-c -osx_image: xcode7.3 +osx_image: xcode8 branches: only: - master @@ -7,20 +7,20 @@ env: global: - LC_CTYPE=en_US.UTF-8 - LANG=en_US.UTF-8 - - IOS_SDK=iphonesimulator9.3 + - IOS_SDK=iphonesimulator10.0 - SCHEME_IOS="TableKit" - PROJECT_FRAMEWORK="TableKit.xcodeproj" matrix: - - DESTINATION="OS=8.1,name=iPhone 4S" SCHEME="$SCHEME_IOS" SDK="$IOS_SDK" - - DESTINATION="OS=8.2,name=iPhone 5" SCHEME="$SCHEME_IOS" SDK="$IOS_SDK" - DESTINATION="OS=9.0,name=iPhone 6" SCHEME="$SCHEME_IOS" SDK="$IOS_SDK" - DESTINATION="OS=9.1,name=iPhone 6 Plus" SCHEME="$SCHEME_IOS" SDK="$IOS_SDK" - DESTINATION="OS=9.2,name=iPhone 6S" SCHEME="$SCHEME_IOS" SDK="$IOS_SDK" - DESTINATION="OS=9.3,name=iPhone 6S Plus" SCHEME="$SCHEME_IOS" SDK="$IOS_SDK" + - DESTINATION="OS=10.0,name=iPhone 5" SCHEME="$SCHEME_IOS" SDK="$IOS_SDK" + - DESTINATION="OS=10.0,name=iPhone 7 Plus" SCHEME="$SCHEME_IOS" SDK="$IOS_SDK" script: - set -o pipefail - xcodebuild -version - xcodebuild -showsdks - - xcodebuild -project "$PROJECT_FRAMEWORK" -scheme "$SCHEME" -sdk "$SDK" -destination "$DESTINATION" -configuration Debug ONLY_ACTIVE_ARCH=NO ENABLE_TESTABILITY=YES test | xcpretty -c; \ No newline at end of file + - xcodebuild -project "$PROJECT_FRAMEWORK" -scheme "$SCHEME" -sdk "$SDK" -destination "$DESTINATION" -configuration Debug ONLY_ACTIVE_ARCH=NO ENABLE_TESTABILITY=YES test | xcpretty; \ No newline at end of file diff --git a/Demo/Classes/Presentation/Controllers/MainController.swift b/Demo/Classes/Presentation/Controllers/MainController.swift index bad5564..dfb92c7 100644 --- a/Demo/Classes/Presentation/Controllers/MainController.swift +++ b/Demo/Classes/Presentation/Controllers/MainController.swift @@ -25,17 +25,17 @@ class MainController: UIViewController { let clickAction = TableRowAction(.click) { [weak self] (data) in - switch data.indexPath.row { + switch (data.indexPath as NSIndexPath).row { case 0: - self?.performSegueWithIdentifier("autolayoutcells", sender: nil) + self?.performSegue(withIdentifier: "autolayoutcells", sender: nil) case 1: - self?.performSegueWithIdentifier("nibcells", sender: nil) + self?.performSegue(withIdentifier: "nibcells", sender: nil) default: break } } - let rows: [Row] = [ + let rows = [ TableRow(item: "Autolayout cells", actions: [clickAction]), TableRow(item: "Nib cells", actions: [clickAction]) @@ -44,4 +44,4 @@ class MainController: UIViewController { // automatically creates a section, also could be used like tableDirector.append(rows: rows) tableDirector += rows } -} \ No newline at end of file +} diff --git a/Demo/Classes/Presentation/Controllers/NibCellsController.swift b/Demo/Classes/Presentation/Controllers/NibCellsController.swift index 5309ebf..e4edd0b 100644 --- a/Demo/Classes/Presentation/Controllers/NibCellsController.swift +++ b/Demo/Classes/Presentation/Controllers/NibCellsController.swift @@ -28,6 +28,6 @@ class NibCellsController: UITableViewController { let rows: [Row] = numbers.map { TableRow(item: $0, actions: [shouldHighlightAction]) } - tableDirector.append(rows: rows) + _ = tableDirector.append(rows: rows) } -} \ No newline at end of file +} diff --git a/Demo/Classes/Presentation/Views/ConfigurableTableViewCell.swift b/Demo/Classes/Presentation/Views/ConfigurableTableViewCell.swift index 3366dee..d685fc3 100644 --- a/Demo/Classes/Presentation/Views/ConfigurableTableViewCell.swift +++ b/Demo/Classes/Presentation/Views/ConfigurableTableViewCell.swift @@ -13,7 +13,7 @@ class ConfigurableTableViewCell: UITableViewCell, ConfigurableCell { func configure(with text: String) { - accessoryType = .DisclosureIndicator + accessoryType = .disclosureIndicator textLabel?.text = text } -} \ No newline at end of file +} diff --git a/Demo/TableKitDemo.xcodeproj/project.pbxproj b/Demo/TableKitDemo.xcodeproj/project.pbxproj index c230c79..de13bdd 100644 --- a/Demo/TableKitDemo.xcodeproj/project.pbxproj +++ b/Demo/TableKitDemo.xcodeproj/project.pbxproj @@ -227,12 +227,13 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0700; + LastUpgradeCheck = 0800; ORGANIZATIONNAME = Tablet; TargetAttributes = { DAB7EB261BEF787300D2AD5E = { CreatedOnToolsVersion = 7.0.1; DevelopmentTeam = Z48R734SJX; + LastSwiftMigration = 0800; }; }; }; @@ -330,8 +331,10 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -374,8 +377,10 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -394,6 +399,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; VALIDATE_PRODUCT = YES; }; name = Release; @@ -401,32 +407,34 @@ DAB7EB3A1BEF787300D2AD5E /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - EMBEDDED_CONTENT_CONTAINS_SWIFT = YES; INFOPLIST_FILE = Resources/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.tablekit.demo; PRODUCT_NAME = TableKitDemo; PROVISIONING_PROFILE = ""; + SWIFT_VERSION = 3.0; }; name = Debug; }; DAB7EB3B1BEF787300D2AD5E /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - EMBEDDED_CONTENT_CONTAINS_SWIFT = YES; INFOPLIST_FILE = Resources/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.tablekit.demo; PRODUCT_NAME = TableKitDemo; PROVISIONING_PROFILE = ""; + SWIFT_VERSION = 3.0; }; name = Release; }; diff --git a/README.md b/README.md index c366ca1..290a649 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,9 @@

Build Status - Swift 2.2 compatible + Swift 2.2 compatible Carthage compatible - CocoaPods compatible + CocoaPods compatible Platform iOS License: MIT

@@ -177,7 +177,7 @@ let click = TableRowAction(.click) { } -let rows: [Row] = users.filter({ $0.state == .active }).map({ TableRow(item: $0.name, actions: [click]) }) +let rows = users.filter({ $0.state == .active }).map({ TableRow(item: $0.name, actions: [click]) }) tableDirector += rows ``` @@ -212,8 +212,8 @@ Clone the repo and drag files from `Sources` folder into your Xcode project. # Requirements -- iOS 8.0+ -- Xcode 7.0+ +- iOS 8.0 +- Xcode 8.0 # License diff --git a/Sources/ConfigurableCell.swift b/Sources/ConfigurableCell.swift index 5ec461e..353e099 100644 --- a/Sources/ConfigurableCell.swift +++ b/Sources/ConfigurableCell.swift @@ -35,7 +35,7 @@ public extension ConfigurableCell where Self: UITableViewCell { static var reuseIdentifier: String { get { - return String(self) + return String(describing: self) } } @@ -52,4 +52,4 @@ public extension ConfigurableCell where Self: UITableViewCell { return nil } } -} \ No newline at end of file +} diff --git a/Sources/HeightStrategy.swift b/Sources/HeightStrategy.swift index 66b715b..850dde9 100644 --- a/Sources/HeightStrategy.swift +++ b/Sources/HeightStrategy.swift @@ -22,24 +22,24 @@ import UIKit public protocol CellHeightCalculatable { - func height(row: Row, path: NSIndexPath) -> CGFloat - func estimatedHeight(row: Row, path: NSIndexPath) -> CGFloat + func height(_ row: Row, path: IndexPath) -> CGFloat + func estimatedHeight(_ row: Row, path: IndexPath) -> CGFloat func invalidate() } -public class PrototypeHeightStrategy: CellHeightCalculatable { +open class PrototypeHeightStrategy: CellHeightCalculatable { private weak var tableView: UITableView? private var prototypes = [String: UITableViewCell]() private var cachedHeights = [Int: CGFloat]() - private var separatorHeight = 1 / UIScreen.mainScreen().scale + private var separatorHeight = 1 / UIScreen.main.scale init(tableView: UITableView?) { self.tableView = tableView } - public func height(row: Row, path: NSIndexPath) -> CGFloat { + open func height(_ row: Row, path: IndexPath) -> CGFloat { guard let tableView = tableView else { return 0 } @@ -52,7 +52,7 @@ public class PrototypeHeightStrategy: CellHeightCalculatable { var prototypeCell = prototypes[row.reuseIdentifier] if prototypeCell == nil { - prototypeCell = tableView.dequeueReusableCellWithIdentifier(row.reuseIdentifier) + prototypeCell = tableView.dequeueReusableCell(withIdentifier: row.reuseIdentifier) prototypes[row.reuseIdentifier] = prototypeCell } @@ -60,18 +60,18 @@ public class PrototypeHeightStrategy: CellHeightCalculatable { row.configure(cell) - cell.bounds = CGRectMake(0, 0, tableView.bounds.size.width, cell.bounds.height) + cell.bounds = CGRect(x: 0, y: 0, width: tableView.bounds.size.width, height: cell.bounds.height) cell.setNeedsLayout() cell.layoutIfNeeded() - let height = cell.contentView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height + (tableView.separatorStyle != .None ? separatorHeight : 0) + let height = cell.contentView.systemLayoutSizeFitting(UILayoutFittingCompressedSize).height + (tableView.separatorStyle != .none ? separatorHeight : 0) cachedHeights[hash] = height return height } - public func estimatedHeight(row: Row, path: NSIndexPath) -> CGFloat { + open func estimatedHeight(_ row: Row, path: IndexPath) -> CGFloat { guard let tableView = tableView else { return 0 } @@ -81,14 +81,14 @@ public class PrototypeHeightStrategy: CellHeightCalculatable { return height } - if let estimatedHeight = row.estimatedHeight where estimatedHeight > 0 { + if let estimatedHeight = row.estimatedHeight , estimatedHeight > 0 { return estimatedHeight } return UITableViewAutomaticDimension } - public func invalidate() { + open func invalidate() { cachedHeights.removeAll() } -} \ No newline at end of file +} diff --git a/Sources/Operators.swift b/Sources/Operators.swift index 3f0f555..f4e719d 100644 --- a/Sources/Operators.swift +++ b/Sources/Operators.swift @@ -20,27 +20,27 @@ // -- public func +=(left: TableDirector, right: TableSection) { - left.append(section: right) + _ = left.append(section: right) } public func +=(left: TableDirector, right: [TableSection]) { - left.append(sections: right) + _ = left.append(sections: right) } // -- public func +=(left: TableDirector, right: Row) { - left.append(sections: [TableSection(rows: [right])]) + _ = left.append(sections: [TableSection(rows: [right])]) } public func +=(left: TableDirector, right: [Row]) { - left.append(sections: [TableSection(rows: right)]) + _ = left.append(sections: [TableSection(rows: right)]) } // -- public func +=(left: TableSection, right: Row) { - left.append(row: right) + _ = left.append(row: right) } public func +=(left: TableSection, right: [Row]) { - left.append(rows: right) -} \ No newline at end of file + _ = left.append(rows: right) +} diff --git a/Sources/TableCellAction.swift b/Sources/TableCellAction.swift index 5f12ca8..0e30413 100644 --- a/Sources/TableCellAction.swift +++ b/Sources/TableCellAction.swift @@ -28,25 +28,25 @@ struct TableKitNotifications { A custom action that you can trigger from your cell. You can easily catch actions using a chaining manner with your row. */ -public class TableCellAction { +open class TableCellAction { /// The cell that triggers an action. - public let cell: UITableViewCell + open let cell: UITableViewCell /// The action unique key. - public let key: String + open let key: String /// The custom user info. - public let userInfo: [NSObject: AnyObject]? + open let userInfo: [AnyHashable: Any]? - public init(key: String, sender: UITableViewCell, userInfo: [NSObject: AnyObject]? = nil) { + public init(key: String, sender: UITableViewCell, userInfo: [AnyHashable: Any]? = nil) { self.key = key self.cell = sender self.userInfo = userInfo } - public func invoke() { - NSNotificationCenter.defaultCenter().postNotificationName(TableKitNotifications.CellAction, object: self, userInfo: userInfo) + open func invoke() { + NotificationCenter.default.post(name: Notification.Name(rawValue: TableKitNotifications.CellAction), object: self, userInfo: userInfo) } -} \ No newline at end of file +} diff --git a/Sources/TableCellRegisterer.swift b/Sources/TableCellRegisterer.swift index 393afa0..17928b8 100644 --- a/Sources/TableCellRegisterer.swift +++ b/Sources/TableCellRegisterer.swift @@ -29,30 +29,30 @@ class TableCellRegisterer { self.tableView = tableView } - func register(cellType cellType: AnyClass, forCellReuseIdentifier reuseIdentifier: String) { + func register(cellType: AnyClass, forCellReuseIdentifier reuseIdentifier: String) { if registeredIds.contains(reuseIdentifier) { return } // check if cell is already registered, probably cell has been registered by storyboard - if tableView?.dequeueReusableCellWithIdentifier(reuseIdentifier) != nil { + if tableView?.dequeueReusableCell(withIdentifier: reuseIdentifier) != nil { registeredIds.insert(reuseIdentifier) return } - let bundle = NSBundle(forClass: cellType) + let bundle = Bundle(for: cellType) // we hope that cell's xib file has name that equals to cell's class name // in that case we could register nib - if let _ = bundle.pathForResource(reuseIdentifier, ofType: "nib") { - tableView?.registerNib(UINib(nibName: reuseIdentifier, bundle: bundle), forCellReuseIdentifier: reuseIdentifier) + if let _ = bundle.path(forResource: reuseIdentifier, ofType: "nib") { + tableView?.register(UINib(nibName: reuseIdentifier, bundle: bundle), forCellReuseIdentifier: reuseIdentifier) // otherwise, register cell class } else { - tableView?.registerClass(cellType, forCellReuseIdentifier: reuseIdentifier) + tableView?.register(cellType, forCellReuseIdentifier: reuseIdentifier) } registeredIds.insert(reuseIdentifier) } -} \ No newline at end of file +} diff --git a/Sources/TableDirector.swift b/Sources/TableDirector.swift index 88c90ea..3cda756 100644 --- a/Sources/TableDirector.swift +++ b/Sources/TableDirector.swift @@ -23,16 +23,16 @@ import UIKit /** Responsible for table view's datasource and delegate. */ -public class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate { +open class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate { - public private(set) weak var tableView: UITableView? - public private(set) var sections = [TableSection]() + open private(set) weak var tableView: UITableView? + open private(set) var sections = [TableSection]() private weak var scrollDelegate: UIScrollViewDelegate? private var heightStrategy: CellHeightCalculatable? private var cellRegisterer: TableCellRegisterer? - public var shouldUsePrototypeCellHeightCalculation: Bool = false { + open var shouldUsePrototypeCellHeightCalculation: Bool = false { didSet { if shouldUsePrototypeCellHeightCalculation { heightStrategy = PrototypeHeightStrategy(tableView: tableView) @@ -40,7 +40,7 @@ public class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate } } - public var isEmpty: Bool { + open var isEmpty: Bool { return sections.isEmpty } @@ -56,57 +56,57 @@ public class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate self.tableView?.delegate = self self.tableView?.dataSource = self - NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(didReceiveAction), name: TableKitNotifications.CellAction, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(didReceiveAction), name: NSNotification.Name(rawValue: TableKitNotifications.CellAction), object: nil) } deinit { - NSNotificationCenter.defaultCenter().removeObserver(self) + NotificationCenter.default.removeObserver(self) } - public func reload() { + open func reload() { tableView?.reloadData() } // MARK: Public - public func invoke(action action: TableRowActionType, cell: UITableViewCell?, indexPath: NSIndexPath) -> Any? { - return sections[indexPath.section].rows[indexPath.row].invoke(action, cell: cell, path: indexPath) + open func invoke(action: TableRowActionType, cell: UITableViewCell?, indexPath: IndexPath) -> Any? { + return sections[(indexPath as NSIndexPath).section].rows[(indexPath as NSIndexPath).row].invoke(action, cell: cell, path: indexPath) } - public override func respondsToSelector(selector: Selector) -> Bool { - return super.respondsToSelector(selector) || scrollDelegate?.respondsToSelector(selector) == true + open override func responds(to selector: Selector) -> Bool { + return super.responds(to: selector) || scrollDelegate?.responds(to: selector) == true } - public override func forwardingTargetForSelector(selector: Selector) -> AnyObject? { - return scrollDelegate?.respondsToSelector(selector) == true ? scrollDelegate : super.forwardingTargetForSelector(selector) + open override func forwardingTarget(for selector: Selector) -> Any? { + return scrollDelegate?.responds(to: selector) == true ? scrollDelegate : super.forwardingTarget(for: selector) } // MARK: - Internal - - func hasAction(action: TableRowActionType, atIndexPath indexPath: NSIndexPath) -> Bool { - return sections[indexPath.section].rows[indexPath.row].hasAction(action) + func hasAction(_ action: TableRowActionType, atIndexPath indexPath: IndexPath) -> Bool { + return sections[(indexPath as NSIndexPath).section].rows[(indexPath as NSIndexPath).row].hasAction(action) } - func didReceiveAction(notification: NSNotification) { + func didReceiveAction(_ notification: Notification) { - guard let action = notification.object as? TableCellAction, indexPath = tableView?.indexPathForCell(action.cell) else { return } - invoke(action: .custom(action.key), cell: action.cell, indexPath: indexPath) + 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) } // MARK: - Height - public func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { + open func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat { - let row = sections[indexPath.section].rows[indexPath.row] + let row = sections[(indexPath as NSIndexPath).section].rows[(indexPath as NSIndexPath).row] cellRegisterer?.register(cellType: row.cellType, forCellReuseIdentifier: row.reuseIdentifier) return row.estimatedHeight ?? heightStrategy?.estimatedHeight(row, path: indexPath) ?? UITableViewAutomaticDimension } - public func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { + open func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { - let row = sections[indexPath.section].rows[indexPath.row] + let row = sections[(indexPath as NSIndexPath).section].rows[(indexPath as NSIndexPath).row] let rowHeight = invoke(action: .height, cell: nil, indexPath: indexPath) as? CGFloat @@ -115,57 +115,57 @@ public class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate // MARK: UITableViewDataSource - configuration - public func numberOfSectionsInTableView(tableView: UITableView) -> Int { + open func numberOfSections(in tableView: UITableView) -> Int { return sections.count } - public func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + open func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return sections[section].numberOfRows } - public func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { + open func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let row = sections[indexPath.section].rows[indexPath.row] - let cell = tableView.dequeueReusableCellWithIdentifier(row.reuseIdentifier, forIndexPath: indexPath) + let row = sections[(indexPath as NSIndexPath).section].rows[(indexPath as NSIndexPath).row] + let cell = tableView.dequeueReusableCell(withIdentifier: row.reuseIdentifier, for: indexPath) if cell.frame.size.width != tableView.frame.size.width { - cell.frame = CGRectMake(0, 0, tableView.frame.size.width, cell.frame.size.height) + cell.frame = CGRect(x: 0, y: 0, width: tableView.frame.size.width, height: cell.frame.size.height) cell.layoutIfNeeded() } row.configure(cell) - invoke(action: .configure, cell: cell, indexPath: indexPath) + _ = invoke(action: .configure, cell: cell, indexPath: indexPath) return cell } // MARK: UITableViewDataSource - section setup - public func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? { + open func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { return sections[section].headerTitle } - public func tableView(tableView: UITableView, titleForFooterInSection section: Int) -> String? { + open func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? { return sections[section].footerTitle } // MARK: UITableViewDelegate - section setup - public func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { + open func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { return sections[section].headerView } - public func tableView(tableView: UITableView, viewForFooterInSection section: Int) -> UIView? { + open func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? { return sections[section].footerView } - public func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { + open func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { let section = sections[section] return section.headerHeight ?? section.headerView?.frame.size.height ?? 0 } - public func tableView(tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat { + open func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat { let section = sections[section] return section.footerHeight ?? section.footerView?.frame.size.height ?? 0 @@ -173,89 +173,89 @@ public class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate // MARK: UITableViewDelegate - actions - public func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { + open func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - let cell = tableView.cellForRowAtIndexPath(indexPath) + let cell = tableView.cellForRow(at: indexPath) if invoke(action: .click, cell: cell, indexPath: indexPath) != nil { - tableView.deselectRowAtIndexPath(indexPath, animated: true) + tableView.deselectRow(at: indexPath, animated: true) } else { - invoke(action: .select, cell: cell, indexPath: indexPath) + _ = invoke(action: .select, cell: cell, indexPath: indexPath) } } - public func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) { - invoke(action: .deselect, cell: tableView.cellForRowAtIndexPath(indexPath), indexPath: indexPath) + open func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) { + _ = invoke(action: .deselect, cell: tableView.cellForRow(at: indexPath), indexPath: indexPath) } - public func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) { - invoke(action: .willDisplay, cell: cell, indexPath: indexPath) + open func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { + _ = invoke(action: .willDisplay, cell: cell, indexPath: indexPath) } - public func tableView(tableView: UITableView, shouldHighlightRowAtIndexPath indexPath: NSIndexPath) -> Bool { - return invoke(action: .shouldHighlight, cell: tableView.cellForRowAtIndexPath(indexPath), indexPath: indexPath) as? Bool ?? true + open func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool { + return invoke(action: .shouldHighlight, cell: tableView.cellForRow(at: indexPath), indexPath: indexPath) as? Bool ?? true } - public func tableView(tableView: UITableView, willSelectRowAtIndexPath indexPath: NSIndexPath) -> NSIndexPath? { + open func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? { if hasAction(.willSelect, atIndexPath: indexPath) { - return invoke(action: .willSelect, cell: tableView.cellForRowAtIndexPath(indexPath), indexPath: indexPath) as? NSIndexPath + return invoke(action: .willSelect, cell: tableView.cellForRow(at: indexPath), indexPath: indexPath) as? IndexPath } return indexPath } // MARK: - Row editing - - public func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool { - return sections[indexPath.section].rows[indexPath.row].isEditingAllowed(forIndexPath: indexPath) + open func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { + return sections[(indexPath as NSIndexPath).section].rows[(indexPath as NSIndexPath).row].isEditingAllowed(forIndexPath: indexPath) } - public func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? { - return sections[indexPath.section].rows[indexPath.row].editingActions + open func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? { + return sections[(indexPath as NSIndexPath).section].rows[(indexPath as NSIndexPath).row].editingActions } - public func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) { + open func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) { - if editingStyle == .Delete { - invoke(action: .clickDelete, cell: tableView.cellForRowAtIndexPath(indexPath), indexPath: indexPath) + if editingStyle == .delete { + _ = invoke(action: .clickDelete, cell: tableView.cellForRow(at: indexPath), indexPath: indexPath) } } // MARK: - Sections manipulation - - public func append(section section: TableSection) -> Self { + open func append(section: TableSection) -> Self { - append(sections: [section]) + _ = append(sections: [section]) return self } - public func append(sections sections: [TableSection]) -> Self { + open func append(sections: [TableSection]) -> Self { - self.sections.appendContentsOf(sections) + self.sections.append(contentsOf: sections) return self } - public func append(rows rows: [Row]) -> Self { + open func append(rows: [Row]) -> Self { - append(section: TableSection(rows: rows)) + _ = append(section: TableSection(rows: rows)) return self } - public func insert(section section: TableSection, atIndex index: Int) -> Self { + open func insert(section: TableSection, atIndex index: Int) -> Self { - sections.insert(section, atIndex: index) + sections.insert(section, at: index) return self } - public func delete(index index: Int) -> Self { + open func delete(index: Int) -> Self { - sections.removeAtIndex(index) + sections.remove(at: index) return self } - public func clear() -> Self { + open func clear() -> Self { sections.removeAll() return self } -} \ No newline at end of file +} diff --git a/Sources/TableRow.swift b/Sources/TableRow.swift index 0655c10..ad440b3 100644 --- a/Sources/TableRow.swift +++ b/Sources/TableRow.swift @@ -22,16 +22,16 @@ import UIKit public protocol RowConfigurable { - func configure(cell: UITableViewCell) + func configure(_ cell: UITableViewCell) } public protocol RowActionable { var editingActions: [UITableViewRowAction]? { get } - func isEditingAllowed(forIndexPath indexPath: NSIndexPath) -> Bool + func isEditingAllowed(forIndexPath indexPath: IndexPath) -> Bool - func invoke(action: TableRowActionType, cell: UITableViewCell?, path: NSIndexPath) -> Any? - func hasAction(action: TableRowActionType) -> Bool + func invoke(_ action: TableRowActionType, cell: UITableViewCell?, path: IndexPath) -> Any? + func hasAction(_ action: TableRowActionType) -> Bool } public protocol RowHashable { @@ -48,29 +48,29 @@ public protocol Row: RowConfigurable, RowActionable, RowHashable { var defaultHeight: CGFloat? { get } } -public class TableRow: Row { +open class TableRow: Row where CellType.T == ItemType, CellType: UITableViewCell { - public let item: ItemType + open let item: ItemType private lazy var actions = [String: TableRowAction]() - private(set) public var editingActions: [UITableViewRowAction]? + private(set) open var editingActions: [UITableViewRowAction]? - public var hashValue: Int { + open var hashValue: Int { return ObjectIdentifier(self).hashValue } - public var reuseIdentifier: String { + open var reuseIdentifier: String { return CellType.reuseIdentifier } - public var estimatedHeight: CGFloat? { + open var estimatedHeight: CGFloat? { return CellType.estimatedHeight } - public var defaultHeight: CGFloat? { + open var defaultHeight: CGFloat? { return CellType.defaultHeight } - public var cellType: AnyClass { + open var cellType: AnyClass { return CellType.self } @@ -83,21 +83,21 @@ public class TableRow Any? { + open func invoke(_ action: TableRowActionType, cell: UITableViewCell?, path: IndexPath) -> Any? { return actions[action.key]?.invoke(item: item, cell: cell, path: path) } - public func hasAction(action: TableRowActionType) -> Bool { + open func hasAction(_ action: TableRowActionType) -> Bool { return actions[action.key] != nil } - public func isEditingAllowed(forIndexPath indexPath: NSIndexPath) -> Bool { + open func isEditingAllowed(forIndexPath indexPath: IndexPath) -> Bool { if actions[TableRowActionType.canEdit.key] != nil { return invoke(.canEdit, cell: nil, path: indexPath) as? Bool ?? false @@ -107,15 +107,15 @@ public class TableRow) -> Self { + open func action(_ action: TableRowAction) -> Self { actions[action.type.key] = action return self } - public func action(type: TableRowActionType, handler: (data: TableRowActionData) -> T) -> Self { + open func action(_ type: TableRowActionType, handler: @escaping (_ data: TableRowActionData) -> T) -> Self { - actions[type.key] = TableRowAction(type, handler: handler) + actions[type.key] = TableRowAction(type, handler: handler) return self } -} \ No newline at end of file +} diff --git a/Sources/TableRowAction.swift b/Sources/TableRowAction.swift index abae255..dac4b49 100644 --- a/Sources/TableRowAction.swift +++ b/Sources/TableRowAction.swift @@ -45,14 +45,14 @@ public enum TableRowActionType { } } -public class TableRowActionData { +open class TableRowActionData where CellType.T == ItemType, CellType: UITableViewCell { - public let item: ItemType - public let cell: CellType? - public let indexPath: NSIndexPath - public let userInfo: [NSObject: AnyObject]? + open let item: ItemType + open let cell: CellType? + open let indexPath: IndexPath + open let userInfo: [AnyHashable: Any]? - init(item: ItemType, cell: CellType?, path: NSIndexPath, userInfo: [NSObject: AnyObject]?) { + init(item: ItemType, cell: CellType?, path: IndexPath, userInfo: [AnyHashable: Any]?) { self.item = item self.cell = cell @@ -61,24 +61,40 @@ public class TableRowActionData { +private enum TableRowActionHandler where CellType.T == ItemType, CellType: UITableViewCell { - public let type: TableRowActionType - private let handler: ((data: TableRowActionData) -> Any?) + case voidAction((TableRowActionData) -> Void) + case action((TableRowActionData) -> Any?) - public init(_ type: TableRowActionType, handler: (data: TableRowActionData) -> Void) { + func invoke(item: ItemType, cell: UITableViewCell?, path: IndexPath) -> Any? { + + switch self { + case .voidAction(let handler): + return handler(TableRowActionData(item: item, cell: cell as? CellType, path: path, userInfo: nil)) + case .action(let handler): + return handler(TableRowActionData(item: item, cell: cell as? CellType, path: path, userInfo: nil)) + } + } +} + +open class TableRowAction where CellType.T == ItemType, CellType: UITableViewCell { + + open let type: TableRowActionType + private let handler: TableRowActionHandler + + public init(_ type: TableRowActionType, handler: @escaping (_ data: TableRowActionData) -> Void) { self.type = type - self.handler = handler + self.handler = .voidAction(handler) } - public init(_ type: TableRowActionType, handler: (data: TableRowActionData) -> T) { + public init(_ type: TableRowActionType, handler: @escaping (_ data: TableRowActionData) -> T) { self.type = type - self.handler = handler + self.handler = .action(handler) } - func invoke(item item: ItemType, cell: UITableViewCell?, path: NSIndexPath) -> Any? { - return handler(data: TableRowActionData(item: item, cell: cell as? CellType, path: path, userInfo: nil)) + func invoke(item: ItemType, cell: UITableViewCell?, path: IndexPath) -> Any? { + return handler.invoke(item: item, cell: cell, path: path) } -} \ No newline at end of file +} diff --git a/Sources/TableSection.swift b/Sources/TableSection.swift index 904bfbd..127ee0e 100644 --- a/Sources/TableSection.swift +++ b/Sources/TableSection.swift @@ -20,31 +20,31 @@ import UIKit -public class TableSection { +open class TableSection { - public private(set) var rows = [Row]() + open private(set) var rows = [Row]() - public var headerTitle: String? - public var footerTitle: String? + open var headerTitle: String? + open var footerTitle: String? - public var headerView: UIView? - public var footerView: UIView? + open var headerView: UIView? + open var footerView: UIView? - public var headerHeight: CGFloat? = nil - public var footerHeight: CGFloat? = nil + open var headerHeight: CGFloat? = nil + open var footerHeight: CGFloat? = nil - public var numberOfRows: Int { + open var numberOfRows: Int { return rows.count } - public var isEmpty: Bool { + open var isEmpty: Bool { return rows.isEmpty } public init(rows: [Row]? = nil) { if let initialRows = rows { - self.rows.appendContentsOf(initialRows) + self.rows.append(contentsOf: initialRows) } } @@ -64,31 +64,31 @@ public class TableSection { // MARK: - Public - - public func clear() { + open func clear() { rows.removeAll() } - public func append(row row: Row) { + open func append(row: Row) { append(rows: [row]) } - public func append(rows rows: [Row]) { - self.rows.appendContentsOf(rows) + open func append(rows: [Row]) { + self.rows.append(contentsOf: rows) } - public func insert(row row: Row, at index: Int) { - rows.insert(row, atIndex: index) + open func insert(row: Row, at index: Int) { + rows.insert(row, at: index) } - public func insert(rows rows: [Row], at index: Int) { - self.rows.insertContentsOf(rows, at: index) + open func insert(rows: [Row], at index: Int) { + self.rows.insert(contentsOf: rows, at: index) } - public func replace(rowAt index: Int, with row: Row) { + open func replace(rowAt index: Int, with row: Row) { rows[index] = row } - public func delete(index index: Int) { - rows.removeAtIndex(index) + open func delete(index: Int) { + rows.remove(at: index) } -} \ No newline at end of file +} diff --git a/TableKit.podspec b/TableKit.podspec index 5380a89..43312c0 100644 --- a/TableKit.podspec +++ b/TableKit.podspec @@ -2,10 +2,10 @@ Pod::Spec.new do |s| s.name = 'TableKit' s.module_name = 'TableKit' - s.version = '1.2.0' + s.version = '1.3.0' s.homepage = 'https://github.com/maxsokolov/TableKit' - s.summary = 'Type-safe declarative table views. Swift 2.2 is required.' + s.summary = 'Type-safe declarative table views with Swift.' s.author = { 'Max Sokolov' => 'i@maxsokolov.net' } s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TableKit.xcodeproj/project.pbxproj b/TableKit.xcodeproj/project.pbxproj index fe0e2a7..458862d 100644 --- a/TableKit.xcodeproj/project.pbxproj +++ b/TableKit.xcodeproj/project.pbxproj @@ -174,14 +174,16 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0730; - LastUpgradeCheck = 0730; + LastUpgradeCheck = 0800; ORGANIZATIONNAME = "Max Sokolov"; TargetAttributes = { DA9EA7551D0B679A0021F650 = { CreatedOnToolsVersion = 7.3; + LastSwiftMigration = 0800; }; DA9EA7C31D0EC45F0021F650 = { CreatedOnToolsVersion = 7.3; + LastSwiftMigration = 0800; }; }; }; @@ -270,8 +272,10 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -319,8 +323,10 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -340,6 +346,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; @@ -351,6 +358,7 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; @@ -363,6 +371,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -370,6 +379,7 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; @@ -381,6 +391,7 @@ PRODUCT_BUNDLE_IDENTIFIER = com.tablekit.TableKit; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; + SWIFT_VERSION = 3.0; }; name = Release; }; @@ -392,6 +403,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.tablekit.TableKitTests; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -403,6 +415,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.tablekit.TableKitTests; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; }; name = Release; }; diff --git a/TableKit.xcodeproj/xcshareddata/xcschemes/TableKit.xcscheme b/TableKit.xcodeproj/xcshareddata/xcschemes/TableKit.xcscheme index 6bd5e4d..5a0d771 100644 --- a/TableKit.xcodeproj/xcshareddata/xcschemes/TableKit.xcscheme +++ b/TableKit.xcodeproj/xcshareddata/xcschemes/TableKit.xcscheme @@ -1,6 +1,6 @@ (item: TestData(title: "title")) .action(TableRowAction(.custom(TestTableViewCellOptions.CellAction)) { (data) in @@ -178,16 +178,16 @@ class TabletTests: XCTestCase { expectation.fulfill() }) - testController.view.hidden = false + testController.view.isHidden = false testController.tableDirector += row testController.tableView.reloadData() - let cell = testController.tableView.cellForRowAtIndexPath(NSIndexPath(forRow: 0, inSection: 0)) as? TestTableViewCell + let cell = testController.tableView.cellForRow(at: IndexPath(row: 0, section: 0)) as? TestTableViewCell XCTAssertNotNil(cell, "Cell should exists and should be TestTableViewCell") cell?.raiseAction() - waitForExpectationsWithTimeout(1.0, handler: nil) + waitForExpectations(timeout: 1.0, handler: nil) } -} \ No newline at end of file +}