From 41c7ca60c79b82d51c13dd31567876b6dc1c6054 Mon Sep 17 00:00:00 2001 From: Benji Encz Date: Fri, 26 Jan 2018 12:43:13 -0800 Subject: [PATCH] [Docs] Complete Public API Documentation All public symbols that are considered part of the core API are now documented. This commit suppresses documentation for APIs that will be removed in future releases. --- Sources/AccessibilityFormats.swift | 17 ++++++++-- Sources/CollectionViewDriver.swift | 2 +- Sources/CollectionViewModel.swift | 32 +++++++++++-------- Sources/Diffing.swift | 10 +++++- Sources/SupplementaryViewInfo.swift | 24 ++++++++++---- Sources/TableViewDriver.swift | 6 ++-- Sources/TableViewModel.swift | 22 +++++++++++-- Sources/Typealiases.swift | 7 ++++ Sources/ViewRegistrationMethod.swift | 1 + .../CollectionViewDriverTests.swift | 6 ++-- .../CollectionViewModelTests.swift | 10 +++--- 11 files changed, 99 insertions(+), 38 deletions(-) diff --git a/Sources/AccessibilityFormats.swift b/Sources/AccessibilityFormats.swift index 1014443..8f3246b 100644 --- a/Sources/AccessibilityFormats.swift +++ b/Sources/AccessibilityFormats.swift @@ -16,26 +16,34 @@ import Foundation -/// Wrapper `struct` for the `accessibilityIdentifier` format that should be applied to the cells of a `UITableView` or a `UICollectionView` +// Note: The accessibility types below are not documented as they are not intended to be part +// of the `ReactiveLists` project in the long term. See https://github.com/plangrid/ReactiveLists/issues/77 + +/// :nodoc: public struct CellAccessibilityFormat: ExpressibleByStringLiteral { private let _format: String + /// :nodoc: public init(_ format: String) { self._format = format } + /// :nodoc: public init(stringLiteral value: StringLiteralType) { self._format = value } + /// :nodoc: public init(extendedGraphemeClusterLiteral value: String) { self._format = value } + /// :nodoc: public init(unicodeScalarLiteral value: String) { self._format = value } + /// :nodoc: public func accessibilityIdentifierForIndexPath(_ indexPath: IndexPath) -> String { return self._format.replacingOccurrences(of: "%{section}", with: String(indexPath.section)) .replacingOccurrences(of: "%{item}", with: String(indexPath.item)) @@ -43,26 +51,31 @@ public struct CellAccessibilityFormat: ExpressibleByStringLiteral { } } -/// Wrapper `struct` for the `accessibilityIdentifier` format that should be applied to the headers and footers of a `UITableView` or a `UICollectionView` +/// :nodoc: public struct SupplementaryAccessibilityFormat: ExpressibleByStringLiteral { private let _format: String + /// :nodoc: public init(_ format: String) { self._format = format } + /// :nodoc: public init(stringLiteral value: StringLiteralType) { self._format = value } + /// :nodoc: public init(extendedGraphemeClusterLiteral value: String) { self._format = value } + /// :nodoc: public init(unicodeScalarLiteral value: String) { self._format = value } + /// :nodoc: public func accessibilityIdentifierForSection(_ section: Int) -> String { return self._format.replacingOccurrences(of: "%{section}", with: String(section)) } diff --git a/Sources/CollectionViewDriver.swift b/Sources/CollectionViewDriver.swift index 42ed082..87ae6e6 100644 --- a/Sources/CollectionViewDriver.swift +++ b/Sources/CollectionViewDriver.swift @@ -173,7 +173,7 @@ public class CollectionViewDriver: NSObject, UICollectionViewDataSource, UIColle /// :nodoc: public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - return self.collectionViewModel?[section]?.cellViewModels?.count ?? 0 + return self.collectionViewModel?[section]?.cellViewModels.count ?? 0 } /// :nodoc: diff --git a/Sources/CollectionViewModel.swift b/Sources/CollectionViewModel.swift index 03049e4..e8fadfa 100644 --- a/Sources/CollectionViewModel.swift +++ b/Sources/CollectionViewModel.swift @@ -32,7 +32,7 @@ public protocol CollectionViewCellViewModel { /// Asks the cell model to update the `UICollectionViewCell` with the content /// in the cell model and return the updated cell. - /// - Parameter cell: the cell which contents need to be updated. + /// - Parameter cell: the cell which's content need to be updated. func applyViewModelToCell(_ cell: UICollectionViewCell) } @@ -45,9 +45,14 @@ public extension CollectionViewCellViewModel { /// View model for supplementary views in collection views. public protocol CollectionViewSupplementaryViewModel { + /// Metadata for this supplementary view. var viewInfo: SupplementaryViewInfo? { get } + /// Height of this supplementary view. var height: CGFloat? { get } + /// Asks the supplementary view model to update the `UICollectionReusableView` with the content + /// in the model and return the updated view. + /// - Parameter view: the view which's content need to be update. func applyViewModelToView(_ view: UICollectionReusableView) } @@ -83,9 +88,8 @@ public struct CollectionViewModel { /// /// - Parameter indexPath: the index path for the cell that is being retrieved public subscript(indexPath: IndexPath) -> CollectionViewCellViewModel? { - guard let section = self[indexPath.section], - let cellViewModels = section.cellViewModels, cellViewModels.count > indexPath.item else { return nil } - return cellViewModels[indexPath.item] + guard let section = self[indexPath.section], section.cellViewModels.count > indexPath.item else { return nil } + return section.cellViewModels[indexPath.item] } /// Provides a description of the collection view content in terms of diffing keys. These diffing keys @@ -99,12 +103,12 @@ public struct CollectionViewModel { } // Ensure we have a diffing key for each cell in this section - let cellDiffingKeys: [DiffingKey] = section.cellViewModels?.map { cell in + let cellDiffingKeys: [DiffingKey] = section.cellViewModels.map { cell in guard let cell = cell as? DiffableViewModel else { fatalError("When diffing is enabled you need to provide cells which are DiffableViews.") } return "\(type(of: cell))_\(cell.diffingKey)" - } ?? [] + } return (sectionDiffingKey, cellDiffingKeys) } @@ -115,7 +119,7 @@ public struct CollectionViewModel { /// View model for a collection view section. public struct CollectionViewSectionViewModel { /// Cells to be shown in this section. - let cellViewModels: [CollectionViewCellViewModel]? + let cellViewModels: [CollectionViewCellViewModel] /// View model for the header of this section. let headerViewModel: CollectionViewSupplementaryViewModel? /// View model for the footer of this section. @@ -133,12 +137,12 @@ public struct CollectionViewSectionViewModel { /// Initializes a collection view section view model. /// /// - Parameters: - /// - cellViewModels: the cells in this section, or `nil`. - /// - headerViewModel: the header view model, or `nil`. - /// - footerViewModel: the footer view model, or `nil`. + /// - cellViewModels: the cells in this section. + /// - headerViewModel: the header view model (defaults to `nil`). + /// - footerViewModel: the footer view model (defaults to `nil`). /// - diffingKey: the diffing key, required for automated diffing. public init( - cellViewModels: [CollectionViewCellViewModel]?, + cellViewModels: [CollectionViewCellViewModel], headerViewModel: CollectionViewSupplementaryViewModel? = nil, footerViewModel: CollectionViewSupplementaryViewModel? = nil, diffingKey: String? = nil @@ -167,7 +171,7 @@ extension CollectionViewSectionViewModel { /// :nodoc: public init( - cellViewModels: [CollectionViewCellViewModel]?, + cellViewModels: [CollectionViewCellViewModel], headerHeight: CGFloat? = nil, footerViewModel: CollectionViewSupplementaryViewModel? = nil, diffingKey: String? = nil @@ -182,7 +186,7 @@ extension CollectionViewSectionViewModel { /// :nodoc: public init( - cellViewModels: [CollectionViewCellViewModel]?, + cellViewModels: [CollectionViewCellViewModel], headerViewModel: CollectionViewSupplementaryViewModel? = nil, footerHeight: CGFloat? = nil, diffingKey: String? = nil @@ -197,7 +201,7 @@ extension CollectionViewSectionViewModel { /// :nodoc: public init( - cellViewModels: [CollectionViewCellViewModel]?, + cellViewModels: [CollectionViewCellViewModel], headerHeight: CGFloat? = nil, footerHeight: CGFloat? = nil, diffingKey: String? = nil diff --git a/Sources/Diffing.swift b/Sources/Diffing.swift index d961fb2..fd45594 100644 --- a/Sources/Diffing.swift +++ b/Sources/Diffing.swift @@ -16,8 +16,16 @@ import Foundation -/// A view that can participate in an automatic diffing algorithm. +/// A view model that can participate in an automatic diffing algorithm. public protocol DiffableViewModel { + /// The key used by the diffing algorithm to uniquely identify an element. + /// If you are using automatic diffing on a `*Driver` (which is enabled by default) + /// you are required to provide a key that uniquely identifies each element. + /// + /// Typically you want to base this diffing key on data that is stored in the model. + /// For example: + /// + /// public var diffingKey = { group.identifier } var diffingKey: DiffingKey { get } } diff --git a/Sources/SupplementaryViewInfo.swift b/Sources/SupplementaryViewInfo.swift index 15092a9..eaef61a 100644 --- a/Sources/SupplementaryViewInfo.swift +++ b/Sources/SupplementaryViewInfo.swift @@ -19,21 +19,31 @@ import UIKit /// Metadata thats required for setting up a supplementary view. public struct SupplementaryViewInfo { - + /// Stores how the view was registered (as a class or via a nib file) public let registrationMethod: ViewRegistrationMethod - + /// The reuse identifier for this supplementary view public let reuseIdentifier: String - + /// The kind of supplementary view (e.g. `header` or `footer`) public let kind: SupplementaryViewKind /// `TableViewDataSource` and `CollectionViewDataSource` will automatically apply /// an `accessibilityIdentifier` to the supplementary view based on this format. public let accessibilityFormat: SupplementaryAccessibilityFormat - public init(registrationMethod: ViewRegistrationMethod, - reuseIdentifier: String, - kind: SupplementaryViewKind, - accessibilityFormat: SupplementaryAccessibilityFormat) { + /// Initializes the metadata for a supplementary view. + /// + /// - Parameters: + /// - registrationMethod: describes how the view was registered (as a class or via a nib file) + /// - reuseIdentifier: reuse identifier for this supplementary view + /// - kind: kind of supplementary view (e.g. `header` or `footer`) + /// - accessibilityFormat: a format string that generates an accessibility identifier for + /// the view that will be mapped to this view model. + public init( + registrationMethod: ViewRegistrationMethod, + reuseIdentifier: String, + kind: SupplementaryViewKind, + accessibilityFormat: SupplementaryAccessibilityFormat + ) { self.registrationMethod = registrationMethod self.reuseIdentifier = reuseIdentifier self.kind = kind diff --git a/Sources/TableViewDriver.swift b/Sources/TableViewDriver.swift index 84b4b84..a9f311f 100644 --- a/Sources/TableViewDriver.swift +++ b/Sources/TableViewDriver.swift @@ -64,7 +64,7 @@ open class TableViewDriver: NSObject { /// were moved/inserted/deleted. /// /// For details, see the documentation for `TableViewDriver.tableViewModel`. - private let automaticDiffingEnabled: Bool + private let _automaticDiffingEnabled: Bool private let _shouldDeselectUponSelection: Bool private var _tableViewDiffer: TableViewDiffCalculator? @@ -88,7 +88,7 @@ open class TableViewDriver: NSObject { ) { self.tableViewModel = tableViewModel self.tableView = tableView - self.automaticDiffingEnabled = automaticDiffingEnabled + self._automaticDiffingEnabled = automaticDiffingEnabled self._shouldDeselectUponSelection = shouldDeselectUponSelection super.init() tableView.dataSource = self @@ -164,7 +164,7 @@ open class TableViewDriver: NSObject { return } - if self.automaticDiffingEnabled { + if self._automaticDiffingEnabled { if !self._didReceiveFirstNonNilValue { // For the first non-nil value, we want to reload data, to avoid a weird // animation where we animate in the initial state diff --git a/Sources/TableViewModel.swift b/Sources/TableViewModel.swift index ae86a85..6ced476 100644 --- a/Sources/TableViewModel.swift +++ b/Sources/TableViewModel.swift @@ -103,7 +103,6 @@ public struct TableViewSectionViewModel { public let cellViewModels: [TableViewCellViewModel] /// View model for the header of this section. - public let headerViewModel: TableViewSectionHeaderFooterViewModel? /// View model for the footer of this section. @@ -127,6 +126,14 @@ public struct TableViewSectionViewModel { return self.cellViewModels.isEmpty } + /// Initializes a `TableViewSectionViewModel`. + /// + /// - Parameters: + /// - cellViewModels: the cell view models contained in this section. + /// - headerViewModel: a header view model for this section (defaults to `nil`). + /// - footerViewModel: a footer view model for this section (defaults to `nil`). + /// - collapsed: whether or not this section is collapsed (defaults to `false`). + /// - diffingKey: the diffing key, or `nil`. Required for automated diffing. public init( cellViewModels: [TableViewCellViewModel], headerViewModel: TableViewSectionHeaderFooterViewModel? = nil, @@ -141,6 +148,17 @@ public struct TableViewSectionViewModel { self.diffingKey = diffingKey } + /// Initializes a `TableViewSectionViewModel`. + /// + /// - Parameters: + /// - headerTitle: title for the header, or `nil`. Setting a title will cause a default header + /// to be added to this section. + /// - headerHeight: the height of the default header, if one exists. + /// - cellViewModels: the cell view models contained in this section. + /// - footerTitle: title for the footer, or `nil`. Setting a title will cause a default footer + /// to be added to this section. + /// - footerHeight: the height of the default footer, if one exists. + /// - diffingKey: the diffing key, or `nil`. Required for automated diffing. public init( headerTitle: String?, headerHeight: CGFloat?, @@ -148,7 +166,7 @@ public struct TableViewSectionViewModel { footerTitle: String? = nil, footerHeight: CGFloat? = 0, diffingKey: String? = nil - ) { + ) { self.cellViewModels = cellViewModels self.headerViewModel = PlainHeaderFooterViewModel(title: headerTitle, height: headerHeight) self.footerViewModel = PlainHeaderFooterViewModel(title: footerTitle, height: footerHeight) diff --git a/Sources/Typealiases.swift b/Sources/Typealiases.swift index 1cd4244..74e00b8 100644 --- a/Sources/Typealiases.swift +++ b/Sources/Typealiases.swift @@ -16,10 +16,17 @@ import Foundation +/// :nodoc: public typealias CommitEditingStyleClosure = (UITableViewCellEditingStyle) -> Void +/// :nodoc: public typealias DidSelectClosure = () -> Void +/// :nodoc: public typealias DidDeleteClosure = () -> Void +/// :nodoc: public typealias DidDeselectClosure = () -> Void +/// :nodoc: public typealias WillBeginEditingClosure = () -> Void +/// :nodoc: public typealias DidEndEditingClosure = () -> Void +/// :nodoc: public typealias AccessoryButtonTappedClosure = () -> Void diff --git a/Sources/ViewRegistrationMethod.swift b/Sources/ViewRegistrationMethod.swift index a583460..e3928ea 100644 --- a/Sources/ViewRegistrationMethod.swift +++ b/Sources/ViewRegistrationMethod.swift @@ -26,6 +26,7 @@ public enum ViewRegistrationMethod { } extension ViewRegistrationMethod: Equatable { + /// :nodoc: public static func == (lhs: ViewRegistrationMethod, rhs: ViewRegistrationMethod) -> Bool { switch (lhs, rhs) { case let (.viewClass(lhsClass), .viewClass(rhsClass)): diff --git a/Tests/CollectionView/CollectionViewDriverTests.swift b/Tests/CollectionView/CollectionViewDriverTests.swift index df89c7c..9fb47d6 100644 --- a/Tests/CollectionView/CollectionViewDriverTests.swift +++ b/Tests/CollectionView/CollectionViewDriverTests.swift @@ -32,7 +32,7 @@ final class CollectionViewDriverTests: XCTestCase { self._collectionView = TestCollectionView(frame: CGRect.zero, collectionViewLayout: UICollectionViewLayout()) self._collectionViewModel = CollectionViewModel(sectionModels: [ CollectionViewSectionViewModel( - cellViewModels: nil, + cellViewModels: [], headerViewModel: TestCollectionViewSupplementaryViewModel(height: 10, viewKind: .header, sectionLabel: "A"), footerViewModel: TestCollectionViewSupplementaryViewModel(height: 11, viewKind: .footer, sectionLabel: "A")), CollectionViewSectionViewModel( @@ -44,7 +44,7 @@ final class CollectionViewDriverTests: XCTestCase { headerViewModel: TestCollectionViewSupplementaryViewModel(label: "header_C", height: 30), footerViewModel: nil), CollectionViewSectionViewModel( - cellViewModels: nil, + cellViewModels: [], headerViewModel: TestCollectionViewSupplementaryViewModel(height: nil, viewKind: .header, sectionLabel: "D"), footerViewModel: TestCollectionViewSupplementaryViewModel(height: nil, viewKind: .footer, sectionLabel: "D")), ]) @@ -209,7 +209,7 @@ final class CollectionViewDriverTests: XCTestCase { self._collectionViewDataSource.collectionViewModel = CollectionViewModel(sectionModels: [ CollectionViewSectionViewModel( - cellViewModels: nil, + cellViewModels: [], headerViewModel: TestCollectionViewSupplementaryViewModel(height: 10, viewKind: .header, sectionLabel: "X"), footerViewModel: TestCollectionViewSupplementaryViewModel(height: 11, viewKind: .footer, sectionLabel: "X")), CollectionViewSectionViewModel( diff --git a/Tests/CollectionView/CollectionViewModelTests.swift b/Tests/CollectionView/CollectionViewModelTests.swift index 472ed2c..e3cfb3b 100644 --- a/Tests/CollectionView/CollectionViewModelTests.swift +++ b/Tests/CollectionView/CollectionViewModelTests.swift @@ -29,7 +29,7 @@ final class CollectionViewModelTests: XCTestCase { footerHeight: 50 ) - XCTAssertEqual(sectionModel.cellViewModels?.count, 1) + XCTAssertEqual(sectionModel.cellViewModels.count, 1) XCTAssertEqual(sectionModel.headerViewModel?.height, 40) XCTAssertEqual(sectionModel.footerViewModel?.height, 50) XCTAssertNil(sectionModel.headerViewModel?.viewInfo) @@ -50,7 +50,7 @@ final class CollectionViewModelTests: XCTestCase { ) ) - XCTAssertEqual(sectionModel.cellViewModels?.count, 1) + XCTAssertEqual(sectionModel.cellViewModels.count, 1) XCTAssertNil(sectionModel.headerViewModel?.viewInfo) XCTAssertEqual(sectionModel.headerViewModel?.height, 40) @@ -76,7 +76,7 @@ final class CollectionViewModelTests: XCTestCase { footerHeight: 50 ) - XCTAssertEqual(sectionModel.cellViewModels?.count, 1) + XCTAssertEqual(sectionModel.cellViewModels.count, 1) XCTAssertNil(sectionModel.footerViewModel?.viewInfo) XCTAssertEqual(sectionModel.headerViewModel?.height, 40) @@ -104,7 +104,7 @@ final class CollectionViewModelTests: XCTestCase { ) ) - XCTAssertEqual(sectionModel.cellViewModels?.count, 1) + XCTAssertEqual(sectionModel.cellViewModels.count, 1) XCTAssertEqual(sectionModel.headerViewModel?.height, 40) XCTAssertEqual(sectionModel.footerViewModel?.height, 50) @@ -126,7 +126,7 @@ final class CollectionViewModelTests: XCTestCase { func testSubscripts() { let collectionViewModel = CollectionViewModel(sectionModels: [ CollectionViewSectionViewModel( - cellViewModels: nil, + cellViewModels: [], headerHeight: 42, footerHeight: nil), CollectionViewSectionViewModel(