Skip to content

Commit

Permalink
Merge pull request #41 from allaboutapps/bugfix/FixRaceConditionCrashes
Browse files Browse the repository at this point in the history
Fix crashes on concurrent select/deselect + reload
  • Loading branch information
amuehleder authored Jul 24, 2023
2 parents e08f4af + 4967f0e commit a54cc44
Show file tree
Hide file tree
Showing 10 changed files with 720 additions and 430 deletions.
7 changes: 7 additions & 0 deletions .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 5 additions & 5 deletions DataSource.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
archiveVersion = 1;
classes = {
};
objectVersion = 52;
objectVersion = 54;
objects = {

/* Begin PBXBuildFile section */
196512982417A743004B77AF /* AutoRegisterCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 196512972417A743004B77AF /* AutoRegisterCell.swift */; };
274B6CD42A5FC9C500D3ECAE /* ConcurrentReloadSelectTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 274B6CD32A5FC9C500D3ECAE /* ConcurrentReloadSelectTest.swift */; };
3903C1832428C7410094EF50 /* ExpandableCellViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3903C1822428C7410094EF50 /* ExpandableCellViewController.swift */; };
3903C1852428C7DE0094EF50 /* TextCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3903C1842428C7DE0094EF50 /* TextCell.swift */; };
3903C1872428C7E80094EF50 /* TextCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3903C1862428C7E80094EF50 /* TextCell.xib */; };
Expand Down Expand Up @@ -36,7 +37,6 @@
398248CB1E5CA74A00F802D1 /* UITableViewExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 398248CA1E5CA74A00F802D1 /* UITableViewExtensions.swift */; };
398248CD1E5CA9C600F802D1 /* DataSource+UITableViewDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 398248CC1E5CA9C600F802D1 /* DataSource+UITableViewDelegate.swift */; };
39913AB81E61BBCC00623635 /* SwiftRandom.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39913AB71E61BBCC00623635 /* SwiftRandom.swift */; };
39A848671E5E1D9600D7DBC2 /* DataSourceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39A848661E5E1D9600D7DBC2 /* DataSourceTests.swift */; };
39A848691E5E1D9600D7DBC2 /* DataSource.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 395D14A41B90612D00658680 /* DataSource.framework */; };
39A848751E5E2DEC00D7DBC2 /* DataSource.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = 395D14A41B90612D00658680 /* DataSource.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
39B621801E6D757000BE18EE /* DataSource+UITableViewDataSourcePrefetching.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39B6217F1E6D757000BE18EE /* DataSource+UITableViewDataSourcePrefetching.swift */; };
Expand Down Expand Up @@ -108,6 +108,7 @@

/* Begin PBXFileReference section */
196512972417A743004B77AF /* AutoRegisterCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutoRegisterCell.swift; sourceTree = "<group>"; };
274B6CD32A5FC9C500D3ECAE /* ConcurrentReloadSelectTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConcurrentReloadSelectTest.swift; sourceTree = "<group>"; };
3903C1822428C7410094EF50 /* ExpandableCellViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExpandableCellViewController.swift; sourceTree = "<group>"; };
3903C1842428C7DE0094EF50 /* TextCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextCell.swift; sourceTree = "<group>"; };
3903C1862428C7E80094EF50 /* TextCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = TextCell.xib; sourceTree = "<group>"; };
Expand Down Expand Up @@ -141,7 +142,6 @@
398987531F386B0700C96BF9 /* Example.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Example.entitlements; sourceTree = "<group>"; };
39913AB71E61BBCC00623635 /* SwiftRandom.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftRandom.swift; sourceTree = "<group>"; };
39A848641E5E1D9600D7DBC2 /* DataSourceTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DataSourceTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
39A848661E5E1D9600D7DBC2 /* DataSourceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataSourceTests.swift; sourceTree = "<group>"; };
39A848681E5E1D9600D7DBC2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
39B6217F1E6D757000BE18EE /* DataSource+UITableViewDataSourcePrefetching.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DataSource+UITableViewDataSourcePrefetching.swift"; sourceTree = "<group>"; };
39E9E3A51E6566AD00A3C300 /* PersonCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PersonCell.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -294,8 +294,8 @@
39A848651E5E1D9600D7DBC2 /* DataSourceTests */ = {
isa = PBXGroup;
children = (
39A848661E5E1D9600D7DBC2 /* DataSourceTests.swift */,
39A848681E5E1D9600D7DBC2 /* Info.plist */,
274B6CD32A5FC9C500D3ECAE /* ConcurrentReloadSelectTest.swift */,
);
path = DataSourceTests;
sourceTree = "<group>";
Expand Down Expand Up @@ -553,7 +553,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
39A848671E5E1D9600D7DBC2 /* DataSourceTests.swift in Sources */,
274B6CD42A5FC9C500D3ECAE /* ConcurrentReloadSelectTest.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
143 changes: 82 additions & 61 deletions DataSource/DataSource+UITableViewDataSource.swift
Original file line number Diff line number Diff line change
@@ -1,34 +1,29 @@
//
// DataSource+UITableView.swift
// DataSource
//
// Created by Matthias Buchetics on 21/02/2017.
// Copyright © 2017 aaa - all about apps GmbH. All rights reserved.
//

import UIKit
import Differ
import UIKit

extension DataSource: UITableViewDataSource {

// MARK: Counts
public func numberOfSections(in tableView: UITableView) -> Int {

public func numberOfSections(in _: UITableView) -> Int {
return visibleSections.count
}
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

public func tableView(_: UITableView, numberOfRowsInSection section: Int) -> Int {
return visibleSections[section].numberOfVisibleRows
}

// MARK: Configuration

public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellDescriptor = self.cellDescriptor(at: indexPath)
guard let cellDescriptor = cellDescriptor(at: indexPath) else {
fatalError("[DataSource] no cellDescriptor found for indexPath \(indexPath) with identifier \(visibleRow(at: indexPath)?.identifier)")
}

let cellIdentifier = cellDescriptor.cellIdentifier
let bundle = cellDescriptor.bundle ?? Bundle.main
if registerNibs && !reuseIdentifiers.contains(cellIdentifier) {

if registerNibs, !reuseIdentifiers.contains(cellIdentifier) {
if bundle.path(forResource: cellIdentifier, ofType: "nib") != nil {
tableView.registerNib(cellIdentifier, bundle: bundle)
reuseIdentifiers.insert(cellIdentifier)
Expand All @@ -37,13 +32,15 @@ extension DataSource: UITableViewDataSource {
reuseIdentifiers.insert(cellIdentifier)
}
}

if let closure = cellDescriptor.configureClosure ?? configure {
let row = self.visibleRow(at: indexPath)
guard let row = visibleRow(at: indexPath) else {
fatalError("[DataSource] no visible row found for indexPath \(indexPath)")
}
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath)

closure(row, cell, indexPath)

return cell
} else if let fallbackDataSource = fallbackDataSource {
return fallbackDataSource.tableView(tableView, cellForRowAt: indexPath)
Expand All @@ -53,101 +50,125 @@ extension DataSource: UITableViewDataSource {
}

// MARK: Header & Footer
public func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {

public func tableView(_: UITableView, titleForHeaderInSection section: Int) -> String? {
let sectionDescriptor = self.sectionDescriptor(at: section)

if let closure = sectionDescriptor?.headerClosure ?? sectionHeader {
let header = closure(visibleSection(at: section), section)

guard let visibleSection = visibleSection(at: section) else {
return nil
}

let header = closure(visibleSection, section)

switch header {
case .title(let title):
return title
default:
return nil
}
}

return nil
}
public func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? {

public func tableView(_: UITableView, titleForFooterInSection section: Int) -> String? {
let sectionDescriptor = self.sectionDescriptor(at: section)

if let closure = sectionDescriptor?.footerClosure ?? sectionFooter {
let footer = closure(visibleSection(at: section), section)

guard let visibleSection = visibleSection(at: section) else {
return nil
}

let footer = closure(visibleSection, section)

switch footer {
case .title(let title):
return title
default:
return nil
}
}

return nil
}

// MARK: Editing

public func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
let cellDescriptor = self.cellDescriptor(at: indexPath)
if let closure = cellDescriptor.canEditClosure ?? canEdit {
return closure(visibleRow(at: indexPath), indexPath)

guard let visibleRow = visibleRow(at: indexPath) else {
return false
}


if let closure = cellDescriptor?.canEditClosure ?? canEdit {
return closure(visibleRow, indexPath)
}

return fallbackDataSource?.tableView?(tableView, canEditRowAt: indexPath)
?? false
}

// MARK: Moving & Reordering

public func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
let cellDescriptor = self.cellDescriptor(at: indexPath)

if let closure = cellDescriptor.canMoveClosure ?? canMove {
return closure(visibleRow(at: indexPath), indexPath)

if let closure = cellDescriptor?.canMoveClosure ?? canMove {
guard let visibleRow = visibleRow(at: indexPath) else {
return false
}

return closure(visibleRow, indexPath)
}

return fallbackDataSource?.tableView?(tableView, canMoveRowAt: indexPath)
?? false
}

// MARK: Index

public func sectionIndexTitles(for tableView: UITableView) -> [String]? {
return sectionIndexTitles?()
?? fallbackDataSource?.sectionIndexTitles?(for: tableView)
}

public func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int) -> Int {
return sectionForSectionIndex?(title, index)
?? fallbackDataSource?.tableView?(tableView, sectionForSectionIndexTitle: title, at: index)
?? index
}

// MARK: Data manipulation

public func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
let cellDescriptor = self.cellDescriptor(at: indexPath)

if let closure = cellDescriptor.commitEditingClosure ?? commitEditing {
closure(visibleRow(at: indexPath), editingStyle, indexPath)

if let closure = cellDescriptor?.commitEditingClosure ?? commitEditing {
guard let visibleRow = visibleRow(at: indexPath) else {
return
}

closure(visibleRow, editingStyle, indexPath)
return
}

fallbackDataSource?.tableView?(tableView, commit: editingStyle, forRowAt: indexPath)
}

public func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
let cellDescriptor = self.cellDescriptor(at: sourceIndexPath)

if let closure = cellDescriptor.moveRowClosure ?? moveRow {
closure(visibleRow(at: sourceIndexPath), (sourceIndexPath, destinationIndexPath))

if let closure = cellDescriptor?.moveRowClosure ?? moveRow {
guard let visibleRow = visibleRow(at: sourceIndexPath) else {
return
}

closure(visibleRow, (sourceIndexPath, destinationIndexPath))
return
}

fallbackDataSource?.tableView?(tableView, moveRowAt: sourceIndexPath, to: destinationIndexPath)
}
}
Loading

0 comments on commit a54cc44

Please sign in to comment.