From 2ea0352980a97e99d4430728bce99585634476f2 Mon Sep 17 00:00:00 2001 From: Michael Garfinkle Date: Tue, 10 May 2022 10:19:20 -0700 Subject: [PATCH 1/2] fixed bug where selection state status not always updating on multi-select --- .../TableView/FunctionalTableData+UITableViewDelegate.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Sources/FunctionalTableData/TableView/FunctionalTableData+UITableViewDelegate.swift b/Sources/FunctionalTableData/TableView/FunctionalTableData+UITableViewDelegate.swift index b8a4253..ce7ff45 100644 --- a/Sources/FunctionalTableData/TableView/FunctionalTableData+UITableViewDelegate.swift +++ b/Sources/FunctionalTableData/TableView/FunctionalTableData+UITableViewDelegate.swift @@ -85,6 +85,10 @@ extension FunctionalTableData { } public func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? { + + //This fixes bug when selecting cells quickly in list view; without this could sometimes get behaviour where tableview cell was selected on the screen, but cell state selection status was not update. This may be due to the fact that state status is updated when cellConfig?.actions.selectionAction function is called. This function is only called in didSelectRowAt function, and could potentially not always fire. + guard tableView.cellForRow(at: indexPath) != nil else { return nil } + if tableView.indexPathForSelectedRow == indexPath { return nil } From 785d006593521c739b01016617f9e235680cfa34 Mon Sep 17 00:00:00 2001 From: Michael Garfinkle Date: Tue, 17 May 2022 09:25:26 -0700 Subject: [PATCH 2/2] added fixes so tests would pass --- ...ctionalTableData+UITableViewDelegate.swift | 4 +- ...iffableDataSourceFunctionalDataTests.swift | 4 +- ...iffableDataSourceTableCellReuseTests.swift | 12 ++-- .../FunctionalDataTests.swift | 2 +- .../Helpers/WindowWithTableViewMounted.swift | 63 +++++++++++++++++++ .../TableCellReuseTests.swift | 12 ++-- 6 files changed, 79 insertions(+), 18 deletions(-) create mode 100644 Tests/FunctionalTableDataTests/Helpers/WindowWithTableViewMounted.swift diff --git a/Sources/FunctionalTableData/TableView/FunctionalTableData+UITableViewDelegate.swift b/Sources/FunctionalTableData/TableView/FunctionalTableData+UITableViewDelegate.swift index ce7ff45..04648c5 100644 --- a/Sources/FunctionalTableData/TableView/FunctionalTableData+UITableViewDelegate.swift +++ b/Sources/FunctionalTableData/TableView/FunctionalTableData+UITableViewDelegate.swift @@ -86,8 +86,8 @@ extension FunctionalTableData { public func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? { - //This fixes bug when selecting cells quickly in list view; without this could sometimes get behaviour where tableview cell was selected on the screen, but cell state selection status was not update. This may be due to the fact that state status is updated when cellConfig?.actions.selectionAction function is called. This function is only called in didSelectRowAt function, and could potentially not always fire. - guard tableView.cellForRow(at: indexPath) != nil else { return nil } + // This fixes a bug when selecting cells quickly in a table view; without this, a tableview cell can be selected on the screen, but the cell state selection status is not updated. This may be due to the fact that state status is updated when cellConfig?.actions.selectionAction function is called. This function is only called in didSelectRowAt function, and could potentially not always fire. + guard tableView.cellForRow(at: indexPath) != nil else { return nil } if tableView.indexPathForSelectedRow == indexPath { return nil diff --git a/Tests/FunctionalTableDataTests/DiffableDataSourceFunctionalDataTests.swift b/Tests/FunctionalTableDataTests/DiffableDataSourceFunctionalDataTests.swift index 306b6bd..8ae620e 100644 --- a/Tests/FunctionalTableDataTests/DiffableDataSourceFunctionalDataTests.swift +++ b/Tests/FunctionalTableDataTests/DiffableDataSourceFunctionalDataTests.swift @@ -74,9 +74,7 @@ class DiffableDataSourceFunctionalDataTests: XCTestCase { func testCellAccessibilityIdentifiers() { let tableData = FunctionalTableData(name: nil, diffingStrategy: .diffableDataSource) - let tableView = UITableView() - - tableData.tableView = tableView + tableData.tableView = WindowWithTableViewMounted().tableView let expectation1 = expectation(description: "rendered") let cellConfig = TestCaseCell(key: "cellKey", state: TestCaseState(data: "red"), cellUpdater: TestCaseState.updateView) let section = TableSection(key: "sectionKey", rows: [cellConfig]) diff --git a/Tests/FunctionalTableDataTests/DiffableDataSourceTableCellReuseTests.swift b/Tests/FunctionalTableDataTests/DiffableDataSourceTableCellReuseTests.swift index f3b5cbe..4231376 100644 --- a/Tests/FunctionalTableDataTests/DiffableDataSourceTableCellReuseTests.swift +++ b/Tests/FunctionalTableDataTests/DiffableDataSourceTableCellReuseTests.swift @@ -12,19 +12,19 @@ import Foundation class DiffableDataSourceTableCellReuseTests: XCTestCase { private typealias LabelCell = HostCell - private var tableView: UITableView! + private var window: WindowWithTableViewMounted! private var tableModel: FunctionalTableData! override func setUp() { super.setUp() - tableView = UITableView() + window = WindowWithTableViewMounted() tableModel = FunctionalTableData() - tableModel.tableView = tableView + tableModel.tableView = window.tableView } override func tearDown() { - tableView = nil tableModel = nil + window.tearDownWindow() super.tearDown() } @@ -42,7 +42,7 @@ class DiffableDataSourceTableCellReuseTests: XCTestCase { renderedDisclosureCell.fulfill() } - guard let cellView = self.tableView.visibleCells.first else { + guard let cellView = self.window.tableView.visibleCells.first else { XCTFail("Tableview has no cell views") return } @@ -62,7 +62,7 @@ class DiffableDataSourceTableCellReuseTests: XCTestCase { renderedUnstyledCell.fulfill() } - guard let cellView = self.tableView.visibleCells.first else { + guard let cellView = self.window.tableView.visibleCells.first else { XCTFail("Tableview has no cell views") return } diff --git a/Tests/FunctionalTableDataTests/FunctionalDataTests.swift b/Tests/FunctionalTableDataTests/FunctionalDataTests.swift index b1be944..fa308a5 100644 --- a/Tests/FunctionalTableDataTests/FunctionalDataTests.swift +++ b/Tests/FunctionalTableDataTests/FunctionalDataTests.swift @@ -75,7 +75,7 @@ class FunctionalDataTests: XCTestCase { func testCellAccessibilityIdentifiers() { let tableData = FunctionalTableData() - let tableView = UITableView() + let tableView = WindowWithTableViewMounted().tableView tableData.tableView = tableView let expectation1 = expectation(description: "rendered") diff --git a/Tests/FunctionalTableDataTests/Helpers/WindowWithTableViewMounted.swift b/Tests/FunctionalTableDataTests/Helpers/WindowWithTableViewMounted.swift new file mode 100644 index 0000000..4c01a3e --- /dev/null +++ b/Tests/FunctionalTableDataTests/Helpers/WindowWithTableViewMounted.swift @@ -0,0 +1,63 @@ +import UIKit + + + +final class WindowWithTableViewMounted { + + private var rootWindow: UIWindow! + let tableView = UITableView() + private let tableViewController : TableViewControllerWithTableViewMounted + + init() { + self.tableViewController = TableViewControllerWithTableViewMounted(tableView) + setUpWindowWithTableView() + presentWindow() + } + + private func setUpWindowWithTableView() { + rootWindow = UIWindow(frame: UIScreen.main.bounds) + rootWindow.rootViewController = tableViewController + } + + private func presentWindow() { + rootWindow.isHidden = false + tableViewController.viewWillAppear(false) + tableViewController.viewDidAppear(false) + } + + func tearDownWindow() { + tableViewController.viewWillDisappear(false) + tableViewController.viewDidDisappear(false) + rootWindow.rootViewController = nil + rootWindow.isHidden = true + self.rootWindow = nil + } +} + + +private final class TableViewControllerWithTableViewMounted: UIViewController { + let tableView : UITableView + + init(_ tableView: UITableView) { + self.tableView = tableView + super.init(nibName: nil, bundle: nil) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func loadView() { + super.loadView() + setupTableView() + } + + func setupTableView() { + view.addSubview(tableView) + tableView.translatesAutoresizingMaskIntoConstraints = false + tableView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true + tableView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true + tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true + tableView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true + } +} diff --git a/Tests/FunctionalTableDataTests/TableCellReuseTests.swift b/Tests/FunctionalTableDataTests/TableCellReuseTests.swift index c03299f..c994b3d 100644 --- a/Tests/FunctionalTableDataTests/TableCellReuseTests.swift +++ b/Tests/FunctionalTableDataTests/TableCellReuseTests.swift @@ -13,18 +13,18 @@ import Foundation class TableCellReuseTests: XCTestCase { private typealias LabelCell = HostCell - private var tableView: UITableView! + private var window: WindowWithTableViewMounted! private var tableModel: FunctionalTableData! override func setUp() { super.setUp() - tableView = UITableView() + window = WindowWithTableViewMounted() tableModel = FunctionalTableData() - tableModel.tableView = tableView + tableModel.tableView = window.tableView } override func tearDown() { - tableView = nil + window.tearDownWindow() tableModel = nil super.tearDown() } @@ -43,7 +43,7 @@ class TableCellReuseTests: XCTestCase { renderedDisclosureCell.fulfill() } - guard let cellView = self.tableView.visibleCells.first else { + guard let cellView = self.window.tableView.visibleCells.first else { XCTFail("Tableview has no cell views") return } @@ -63,7 +63,7 @@ class TableCellReuseTests: XCTestCase { renderedUnstyledCell.fulfill() } - guard let cellView = self.tableView.visibleCells.first else { + guard let cellView = self.window.tableView.visibleCells.first else { XCTFail("Tableview has no cell views") return }