Skip to content

Commit a54cc44

Browse files
authored
Merge pull request #41 from allaboutapps/bugfix/FixRaceConditionCrashes
Fix crashes on concurrent select/deselect + reload
2 parents e08f4af + 4967f0e commit a54cc44

File tree

10 files changed

+720
-430
lines changed

10 files changed

+720
-430
lines changed

.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

DataSource.xcodeproj/project.pbxproj

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@
33
archiveVersion = 1;
44
classes = {
55
};
6-
objectVersion = 52;
6+
objectVersion = 54;
77
objects = {
88

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

109109
/* Begin PBXFileReference section */
110110
196512972417A743004B77AF /* AutoRegisterCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutoRegisterCell.swift; sourceTree = "<group>"; };
111+
274B6CD32A5FC9C500D3ECAE /* ConcurrentReloadSelectTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConcurrentReloadSelectTest.swift; sourceTree = "<group>"; };
111112
3903C1822428C7410094EF50 /* ExpandableCellViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExpandableCellViewController.swift; sourceTree = "<group>"; };
112113
3903C1842428C7DE0094EF50 /* TextCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextCell.swift; sourceTree = "<group>"; };
113114
3903C1862428C7E80094EF50 /* TextCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = TextCell.xib; sourceTree = "<group>"; };
@@ -141,7 +142,6 @@
141142
398987531F386B0700C96BF9 /* Example.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Example.entitlements; sourceTree = "<group>"; };
142143
39913AB71E61BBCC00623635 /* SwiftRandom.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftRandom.swift; sourceTree = "<group>"; };
143144
39A848641E5E1D9600D7DBC2 /* DataSourceTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DataSourceTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
144-
39A848661E5E1D9600D7DBC2 /* DataSourceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataSourceTests.swift; sourceTree = "<group>"; };
145145
39A848681E5E1D9600D7DBC2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
146146
39B6217F1E6D757000BE18EE /* DataSource+UITableViewDataSourcePrefetching.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DataSource+UITableViewDataSourcePrefetching.swift"; sourceTree = "<group>"; };
147147
39E9E3A51E6566AD00A3C300 /* PersonCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PersonCell.swift; sourceTree = "<group>"; };
@@ -294,8 +294,8 @@
294294
39A848651E5E1D9600D7DBC2 /* DataSourceTests */ = {
295295
isa = PBXGroup;
296296
children = (
297-
39A848661E5E1D9600D7DBC2 /* DataSourceTests.swift */,
298297
39A848681E5E1D9600D7DBC2 /* Info.plist */,
298+
274B6CD32A5FC9C500D3ECAE /* ConcurrentReloadSelectTest.swift */,
299299
);
300300
path = DataSourceTests;
301301
sourceTree = "<group>";
@@ -553,7 +553,7 @@
553553
isa = PBXSourcesBuildPhase;
554554
buildActionMask = 2147483647;
555555
files = (
556-
39A848671E5E1D9600D7DBC2 /* DataSourceTests.swift in Sources */,
556+
274B6CD42A5FC9C500D3ECAE /* ConcurrentReloadSelectTest.swift in Sources */,
557557
);
558558
runOnlyForDeploymentPostprocessing = 0;
559559
};
Lines changed: 82 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,29 @@
1-
//
2-
// DataSource+UITableView.swift
3-
// DataSource
4-
//
5-
// Created by Matthias Buchetics on 21/02/2017.
6-
// Copyright © 2017 aaa - all about apps GmbH. All rights reserved.
7-
//
8-
9-
import UIKit
101
import Differ
2+
import UIKit
113

124
extension DataSource: UITableViewDataSource {
13-
5+
146
// MARK: Counts
15-
16-
public func numberOfSections(in tableView: UITableView) -> Int {
7+
8+
public func numberOfSections(in _: UITableView) -> Int {
179
return visibleSections.count
1810
}
19-
20-
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
11+
12+
public func tableView(_: UITableView, numberOfRowsInSection section: Int) -> Int {
2113
return visibleSections[section].numberOfVisibleRows
2214
}
23-
15+
2416
// MARK: Configuration
25-
17+
2618
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
27-
let cellDescriptor = self.cellDescriptor(at: indexPath)
19+
guard let cellDescriptor = cellDescriptor(at: indexPath) else {
20+
fatalError("[DataSource] no cellDescriptor found for indexPath \(indexPath) with identifier \(visibleRow(at: indexPath)?.identifier)")
21+
}
22+
2823
let cellIdentifier = cellDescriptor.cellIdentifier
2924
let bundle = cellDescriptor.bundle ?? Bundle.main
30-
31-
if registerNibs && !reuseIdentifiers.contains(cellIdentifier) {
25+
26+
if registerNibs, !reuseIdentifiers.contains(cellIdentifier) {
3227
if bundle.path(forResource: cellIdentifier, ofType: "nib") != nil {
3328
tableView.registerNib(cellIdentifier, bundle: bundle)
3429
reuseIdentifiers.insert(cellIdentifier)
@@ -37,13 +32,15 @@ extension DataSource: UITableViewDataSource {
3732
reuseIdentifiers.insert(cellIdentifier)
3833
}
3934
}
40-
35+
4136
if let closure = cellDescriptor.configureClosure ?? configure {
42-
let row = self.visibleRow(at: indexPath)
37+
guard let row = visibleRow(at: indexPath) else {
38+
fatalError("[DataSource] no visible row found for indexPath \(indexPath)")
39+
}
4340
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath)
44-
41+
4542
closure(row, cell, indexPath)
46-
43+
4744
return cell
4845
} else if let fallbackDataSource = fallbackDataSource {
4946
return fallbackDataSource.tableView(tableView, cellForRowAt: indexPath)
@@ -53,101 +50,125 @@ extension DataSource: UITableViewDataSource {
5350
}
5451

5552
// MARK: Header & Footer
56-
57-
public func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
53+
54+
public func tableView(_: UITableView, titleForHeaderInSection section: Int) -> String? {
5855
let sectionDescriptor = self.sectionDescriptor(at: section)
59-
56+
6057
if let closure = sectionDescriptor?.headerClosure ?? sectionHeader {
61-
let header = closure(visibleSection(at: section), section)
62-
58+
guard let visibleSection = visibleSection(at: section) else {
59+
return nil
60+
}
61+
62+
let header = closure(visibleSection, section)
63+
6364
switch header {
6465
case .title(let title):
6566
return title
6667
default:
6768
return nil
6869
}
6970
}
70-
71+
7172
return nil
7273
}
73-
74-
public func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? {
74+
75+
public func tableView(_: UITableView, titleForFooterInSection section: Int) -> String? {
7576
let sectionDescriptor = self.sectionDescriptor(at: section)
76-
77+
7778
if let closure = sectionDescriptor?.footerClosure ?? sectionFooter {
78-
let footer = closure(visibleSection(at: section), section)
79-
79+
guard let visibleSection = visibleSection(at: section) else {
80+
return nil
81+
}
82+
83+
let footer = closure(visibleSection, section)
84+
8085
switch footer {
8186
case .title(let title):
8287
return title
8388
default:
8489
return nil
8590
}
8691
}
87-
92+
8893
return nil
8994
}
90-
95+
9196
// MARK: Editing
92-
97+
9398
public func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
9499
let cellDescriptor = self.cellDescriptor(at: indexPath)
95-
96-
if let closure = cellDescriptor.canEditClosure ?? canEdit {
97-
return closure(visibleRow(at: indexPath), indexPath)
100+
101+
guard let visibleRow = visibleRow(at: indexPath) else {
102+
return false
98103
}
99-
104+
105+
if let closure = cellDescriptor?.canEditClosure ?? canEdit {
106+
return closure(visibleRow, indexPath)
107+
}
108+
100109
return fallbackDataSource?.tableView?(tableView, canEditRowAt: indexPath)
101110
?? false
102111
}
103-
112+
104113
// MARK: Moving & Reordering
105-
114+
106115
public func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
107116
let cellDescriptor = self.cellDescriptor(at: indexPath)
108-
109-
if let closure = cellDescriptor.canMoveClosure ?? canMove {
110-
return closure(visibleRow(at: indexPath), indexPath)
117+
118+
if let closure = cellDescriptor?.canMoveClosure ?? canMove {
119+
guard let visibleRow = visibleRow(at: indexPath) else {
120+
return false
121+
}
122+
123+
return closure(visibleRow, indexPath)
111124
}
112-
125+
113126
return fallbackDataSource?.tableView?(tableView, canMoveRowAt: indexPath)
114127
?? false
115128
}
116-
129+
117130
// MARK: Index
118-
131+
119132
public func sectionIndexTitles(for tableView: UITableView) -> [String]? {
120133
return sectionIndexTitles?()
121134
?? fallbackDataSource?.sectionIndexTitles?(for: tableView)
122135
}
123-
136+
124137
public func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int) -> Int {
125138
return sectionForSectionIndex?(title, index)
126139
?? fallbackDataSource?.tableView?(tableView, sectionForSectionIndexTitle: title, at: index)
127140
?? index
128141
}
129-
142+
130143
// MARK: Data manipulation
131-
144+
132145
public func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
133146
let cellDescriptor = self.cellDescriptor(at: indexPath)
134-
135-
if let closure = cellDescriptor.commitEditingClosure ?? commitEditing {
136-
closure(visibleRow(at: indexPath), editingStyle, indexPath)
147+
148+
if let closure = cellDescriptor?.commitEditingClosure ?? commitEditing {
149+
guard let visibleRow = visibleRow(at: indexPath) else {
150+
return
151+
}
152+
153+
closure(visibleRow, editingStyle, indexPath)
137154
return
138155
}
139-
156+
140157
fallbackDataSource?.tableView?(tableView, commit: editingStyle, forRowAt: indexPath)
141158
}
142-
159+
143160
public func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
144161
let cellDescriptor = self.cellDescriptor(at: sourceIndexPath)
145-
146-
if let closure = cellDescriptor.moveRowClosure ?? moveRow {
147-
closure(visibleRow(at: sourceIndexPath), (sourceIndexPath, destinationIndexPath))
162+
163+
if let closure = cellDescriptor?.moveRowClosure ?? moveRow {
164+
guard let visibleRow = visibleRow(at: sourceIndexPath) else {
165+
return
166+
}
167+
168+
closure(visibleRow, (sourceIndexPath, destinationIndexPath))
148169
return
149170
}
150-
171+
151172
fallbackDataSource?.tableView?(tableView, moveRowAt: sourceIndexPath, to: destinationIndexPath)
152173
}
153174
}

0 commit comments

Comments
 (0)