diff --git a/.gitignore b/.gitignore
index 19ccb4f..5da9a19 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,3 +22,6 @@ DerivedData
# Carthage
Carthage/Checkouts
Carthage/Build
+
+# Swift Package Manager
+.build/
\ No newline at end of file
diff --git a/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..919434a
--- /dev/null
+++ b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/Cartfile b/Cartfile
index 83454b0..9e7e149 100644
--- a/Cartfile
+++ b/Cartfile
@@ -1 +1 @@
-github "tonyarnold/Differ" ~> 1.4
+github "tonyarnold/Differ" ~> 1.4
\ No newline at end of file
diff --git a/Cartfile.resolved b/Cartfile.resolved
index 9350cdf..28f8b96 100644
--- a/Cartfile.resolved
+++ b/Cartfile.resolved
@@ -1 +1 @@
-github "tonyarnold/Differ" "1.4.0"
+github "tonyarnold/Differ" "1.4.4"
diff --git a/DataSource.xcodeproj/project.pbxproj b/DataSource.xcodeproj/project.pbxproj
index 10c79ac..e0741ec 100644
--- a/DataSource.xcodeproj/project.pbxproj
+++ b/DataSource.xcodeproj/project.pbxproj
@@ -3,10 +3,15 @@
archiveVersion = 1;
classes = {
};
- objectVersion = 46;
+ 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 */; };
390CAF1C1E79AA560024E3E6 /* SectionDescriptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 390CAF1B1E79AA560024E3E6 /* SectionDescriptor.swift */; };
395D14801B90610A00658680 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 395D147F1B90610A00658680 /* AppDelegate.swift */; };
395D14871B90610A00658680 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 395D14861B90610A00658680 /* Assets.xcassets */; };
@@ -32,12 +37,9 @@
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 */; };
- 39D22FF7221C403C00C12A01 /* Differ.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 39D22FF6221C403C00C12A01 /* Differ.framework */; };
- 39D22FF8221C40BB00C12A01 /* Differ.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 39D22FF6221C403C00C12A01 /* Differ.framework */; };
39E9E3A81E6566AD00A3C300 /* PersonCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39E9E3A51E6566AD00A3C300 /* PersonCell.swift */; };
39E9E3A91E6566AD00A3C300 /* TitleCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39E9E3A61E6566AD00A3C300 /* TitleCell.swift */; };
39E9E3AA1E6566AD00A3C300 /* TitleCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 39E9E3A71E6566AD00A3C300 /* TitleCell.xib */; };
@@ -47,9 +49,10 @@
4C6076D821490B00002E8BD1 /* SeparatedSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C6076D721490B00002E8BD1 /* SeparatedSection.swift */; };
4C6076DC21490B4D002E8BD1 /* SeparatorLineCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C6076DA21490B4D002E8BD1 /* SeparatorLineCell.swift */; };
4C6076DF21490C80002E8BD1 /* SeparatedSectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C6076DE21490C80002E8BD1 /* SeparatedSectionViewController.swift */; };
- 4C6076E121490FF3002E8BD1 /* SeparatorLineCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C6076E021490FF3002E8BD1 /* SeparatorLineCell.xib */; };
4CA65F60214F952E004F2F19 /* UIView+AutoLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CA65F5F214F952E004F2F19 /* UIView+AutoLayout.swift */; };
5C61C91820AF0AB0003A08B8 /* SwipeActionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C61C91720AF0AB0003A08B8 /* SwipeActionViewController.swift */; };
+ 5F91D0C625091B8300CF5053 /* ContextMenuViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F91D0C525091B8300CF5053 /* ContextMenuViewController.swift */; };
+ 5FD722022500F36800835AA1 /* Differ in Frameworks */ = {isa = PBXBuildFile; productRef = 5FD722012500F36800835AA1 /* Differ */; };
D8D61BEE21E4DD3E00937D1C /* SeparatorLineViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8D61BED21E4DD3E00937D1C /* SeparatorLineViewModel.swift */; };
D8D61BF021E4E11300937D1C /* SeparatorCustomViewViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8D61BEF21E4E11300937D1C /* SeparatorCustomViewViewModel.swift */; };
/* End PBXBuildFile section */
@@ -104,6 +107,11 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
+ 196512972417A743004B77AF /* AutoRegisterCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutoRegisterCell.swift; sourceTree = ""; };
+ 274B6CD32A5FC9C500D3ECAE /* ConcurrentReloadSelectTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConcurrentReloadSelectTest.swift; sourceTree = ""; };
+ 3903C1822428C7410094EF50 /* ExpandableCellViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExpandableCellViewController.swift; sourceTree = ""; };
+ 3903C1842428C7DE0094EF50 /* TextCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextCell.swift; sourceTree = ""; };
+ 3903C1862428C7E80094EF50 /* TextCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = TextCell.xib; sourceTree = ""; };
390CAF1B1E79AA560024E3E6 /* SectionDescriptor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SectionDescriptor.swift; sourceTree = ""; };
395D147C1B90610A00658680 /* Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Example.app; sourceTree = BUILT_PRODUCTS_DIR; };
395D147F1B90610A00658680 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
@@ -123,7 +131,6 @@
398248A91E5C6DDC00F802D1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
398248AB1E5C6DDC00F802D1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
398248AE1E5C6EFB00F802D1 /* DataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataSource.swift; sourceTree = ""; };
- 398248B31E5C704700F802D1 /* Cartfile */ = {isa = PBXFileReference; lastKnownFileType = text; path = Cartfile; sourceTree = ""; };
398248B41E5C705000F802D1 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; };
398248C01E5C7A3500F802D1 /* Row.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Row.swift; sourceTree = ""; };
398248C21E5C7A4000F802D1 /* Section.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Section.swift; sourceTree = ""; };
@@ -135,10 +142,8 @@
398987531F386B0700C96BF9 /* Example.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Example.entitlements; sourceTree = ""; };
39913AB71E61BBCC00623635 /* SwiftRandom.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftRandom.swift; sourceTree = ""; };
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 = ""; };
39A848681E5E1D9600D7DBC2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
39B6217F1E6D757000BE18EE /* DataSource+UITableViewDataSourcePrefetching.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DataSource+UITableViewDataSourcePrefetching.swift"; sourceTree = ""; };
- 39D22FF6221C403C00C12A01 /* Differ.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Differ.framework; path = Carthage/Build/iOS/Differ.framework; sourceTree = ""; };
39E9E3A51E6566AD00A3C300 /* PersonCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PersonCell.swift; sourceTree = ""; };
39E9E3A61E6566AD00A3C300 /* TitleCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TitleCell.swift; sourceTree = ""; };
39E9E3A71E6566AD00A3C300 /* TitleCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = TitleCell.xib; sourceTree = ""; };
@@ -148,9 +153,9 @@
4C6076D721490B00002E8BD1 /* SeparatedSection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SeparatedSection.swift; sourceTree = ""; };
4C6076DA21490B4D002E8BD1 /* SeparatorLineCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SeparatorLineCell.swift; sourceTree = ""; };
4C6076DE21490C80002E8BD1 /* SeparatedSectionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeparatedSectionViewController.swift; sourceTree = ""; };
- 4C6076E021490FF3002E8BD1 /* SeparatorLineCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SeparatorLineCell.xib; sourceTree = ""; };
4CA65F5F214F952E004F2F19 /* UIView+AutoLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+AutoLayout.swift"; sourceTree = ""; };
5C61C91720AF0AB0003A08B8 /* SwipeActionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwipeActionViewController.swift; sourceTree = ""; };
+ 5F91D0C525091B8300CF5053 /* ContextMenuViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContextMenuViewController.swift; sourceTree = ""; };
D8D61BED21E4DD3E00937D1C /* SeparatorLineViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeparatorLineViewModel.swift; sourceTree = ""; };
D8D61BEF21E4E11300937D1C /* SeparatorCustomViewViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeparatorCustomViewViewModel.swift; sourceTree = ""; };
/* End PBXFileReference section */
@@ -160,7 +165,6 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 39D22FF8221C40BB00C12A01 /* Differ.framework in Frameworks */,
395D14B91B90612D00658680 /* DataSource.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -169,7 +173,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 39D22FF7221C403C00C12A01 /* Differ.framework in Frameworks */,
+ 5FD722022500F36800835AA1 /* Differ in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -187,12 +191,10 @@
395D14731B90610A00658680 = {
isa = PBXGroup;
children = (
- 398248B31E5C704700F802D1 /* Cartfile */,
398248B41E5C705000F802D1 /* README.md */,
395D14A51B90612D00658680 /* DataSource */,
39A848651E5E1D9600D7DBC2 /* DataSourceTests */,
395D147E1B90610A00658680 /* Example */,
- 398248B51E5C707A00F802D1 /* Frameworks */,
395D147D1B90610A00658680 /* Products */,
);
sourceTree = "";
@@ -239,6 +241,7 @@
4C6076D921490B34002E8BD1 /* SeparatedSection */,
395D14A61B90612D00658680 /* DataSource.h */,
395D14A81B90612D00658680 /* Info.plist */,
+ 196512972417A743004B77AF /* AutoRegisterCell.swift */,
);
path = DataSource;
sourceTree = "";
@@ -253,6 +256,8 @@
396E02DF20A1B0090072291F /* SwipeToDeleteViewController.swift */,
5C61C91720AF0AB0003A08B8 /* SwipeActionViewController.swift */,
4C6076DE21490C80002E8BD1 /* SeparatedSectionViewController.swift */,
+ 3903C1822428C7410094EF50 /* ExpandableCellViewController.swift */,
+ 5F91D0C525091B8300CF5053 /* ContextMenuViewController.swift */,
);
name = Examples;
sourceTree = "";
@@ -276,14 +281,6 @@
path = Storyboards;
sourceTree = "";
};
- 398248B51E5C707A00F802D1 /* Frameworks */ = {
- isa = PBXGroup;
- children = (
- 39D22FF6221C403C00C12A01 /* Differ.framework */,
- );
- name = Frameworks;
- sourceTree = "";
- };
39913AB61E61BBB900623635 /* Utilities */ = {
isa = PBXGroup;
children = (
@@ -297,8 +294,8 @@
39A848651E5E1D9600D7DBC2 /* DataSourceTests */ = {
isa = PBXGroup;
children = (
- 39A848661E5E1D9600D7DBC2 /* DataSourceTests.swift */,
39A848681E5E1D9600D7DBC2 /* Info.plist */,
+ 274B6CD32A5FC9C500D3ECAE /* ConcurrentReloadSelectTest.swift */,
);
path = DataSourceTests;
sourceTree = "";
@@ -311,6 +308,8 @@
39E9E3AB1E659D6C00A3C300 /* TextFieldCell.swift */,
39E9E3A61E6566AD00A3C300 /* TitleCell.swift */,
39E9E3A71E6566AD00A3C300 /* TitleCell.xib */,
+ 3903C1842428C7DE0094EF50 /* TextCell.swift */,
+ 3903C1862428C7E80094EF50 /* TextCell.xib */,
);
path = Cells;
sourceTree = "";
@@ -322,7 +321,6 @@
D8D61BED21E4DD3E00937D1C /* SeparatorLineViewModel.swift */,
D8D61BEF21E4E11300937D1C /* SeparatorCustomViewViewModel.swift */,
4C6076DA21490B4D002E8BD1 /* SeparatorLineCell.swift */,
- 4C6076E021490FF3002E8BD1 /* SeparatorLineCell.xib */,
);
path = SeparatedSection;
sourceTree = "";
@@ -357,7 +355,6 @@
395D14791B90610A00658680 /* Frameworks */,
395D147A1B90610A00658680 /* Resources */,
395D14BE1B90612D00658680 /* Embed Frameworks */,
- 398248B81E5C70B900F802D1 /* Carthage */,
);
buildRules = (
);
@@ -373,9 +370,9 @@
isa = PBXNativeTarget;
buildConfigurationList = 395D14BB1B90612D00658680 /* Build configuration list for PBXNativeTarget "DataSource" */;
buildPhases = (
+ 395D14A11B90612D00658680 /* Headers */,
395D149F1B90612D00658680 /* Sources */,
395D14A01B90612D00658680 /* Frameworks */,
- 395D14A11B90612D00658680 /* Headers */,
395D14A21B90612D00658680 /* Resources */,
);
buildRules = (
@@ -383,6 +380,9 @@
dependencies = (
);
name = DataSource;
+ packageProductDependencies = (
+ 5FD722012500F36800835AA1 /* Differ */,
+ );
productName = DataSource;
productReference = 395D14A41B90612D00658680 /* DataSource.framework */;
productType = "com.apple.product-type.framework";
@@ -414,7 +414,7 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0820;
- LastUpgradeCheck = 1020;
+ LastUpgradeCheck = 1330;
ORGANIZATIONNAME = "aaa - all about apps GmbH";
TargetAttributes = {
395D147B1B90610A00658680 = {
@@ -455,6 +455,9 @@
Base,
);
mainGroup = 395D14731B90610A00658680;
+ packageReferences = (
+ 5FD722002500F36800835AA1 /* XCRemoteSwiftPackageReference "Differ" */,
+ );
productRefGroup = 395D147D1B90610A00658680 /* Products */;
projectDirPath = "";
projectRoot = "";
@@ -473,6 +476,7 @@
files = (
398248AC1E5C6DDC00F802D1 /* LaunchScreen.storyboard in Resources */,
395D14871B90610A00658680 /* Assets.xcassets in Resources */,
+ 3903C1872428C7E80094EF50 /* TextCell.xib in Resources */,
39E9E3AA1E6566AD00A3C300 /* TitleCell.xib in Resources */,
398248AD1E5C6DDC00F802D1 /* Main.storyboard in Resources */,
);
@@ -482,7 +486,6 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- 4C6076E121490FF3002E8BD1 /* SeparatorLineCell.xib in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -495,24 +498,6 @@
};
/* End PBXResourcesBuildPhase section */
-/* Begin PBXShellScriptBuildPhase section */
- 398248B81E5C70B900F802D1 /* Carthage */ = {
- isa = PBXShellScriptBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- inputPaths = (
- "$(SRCROOT)/Carthage/Build/iOS/Differ.framework",
- );
- name = Carthage;
- outputPaths = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- shellPath = /bin/sh;
- shellScript = "/usr/local/bin/carthage copy-frameworks\n";
- };
-/* End PBXShellScriptBuildPhase section */
-
/* Begin PBXSourcesBuildPhase section */
395D14781B90610A00658680 /* Sources */ = {
isa = PBXSourcesBuildPhase;
@@ -522,9 +507,12 @@
5C61C91820AF0AB0003A08B8 /* SwipeActionViewController.swift in Sources */,
3968B9141E7C103400EE876F /* LazyRowsViewController.swift in Sources */,
39913AB81E61BBCC00623635 /* SwiftRandom.swift in Sources */,
+ 3903C1852428C7DE0094EF50 /* TextCell.swift in Sources */,
396E02E020A1B0090072291F /* SwipeToDeleteViewController.swift in Sources */,
3968B9161E7C261600EE876F /* UILabel+Animation.swift in Sources */,
+ 5F91D0C625091B8300CF5053 /* ContextMenuViewController.swift in Sources */,
39E9E3AE1E659D7D00A3C300 /* SwitchCell.swift in Sources */,
+ 3903C1832428C7410094EF50 /* ExpandableCellViewController.swift in Sources */,
39E9E3A91E6566AD00A3C300 /* TitleCell.swift in Sources */,
3968B9111E7C103400EE876F /* RandomPersonsViewController.swift in Sources */,
395D14801B90610A00658680 /* AppDelegate.swift in Sources */,
@@ -544,6 +532,7 @@
D8D61BF021E4E11300937D1C /* SeparatorCustomViewViewModel.swift in Sources */,
398248CB1E5CA74A00F802D1 /* UITableViewExtensions.swift in Sources */,
398248CD1E5CA9C600F802D1 /* DataSource+UITableViewDelegate.swift in Sources */,
+ 196512982417A743004B77AF /* AutoRegisterCell.swift in Sources */,
398248C51E5C7A5600F802D1 /* CellDescriptor.swift in Sources */,
4CA65F60214F952E004F2F19 /* UIView+AutoLayout.swift in Sources */,
398248C31E5C7A4000F802D1 /* Section.swift in Sources */,
@@ -564,7 +553,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- 39A848671E5E1D9600D7DBC2 /* DataSourceTests.swift in Sources */,
+ 274B6CD42A5FC9C500D3ECAE /* ConcurrentReloadSelectTest.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -630,6 +619,7 @@
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
@@ -654,7 +644,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 10.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@@ -684,6 +674,7 @@
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
@@ -702,7 +693,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 10.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES;
@@ -715,13 +706,19 @@
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ CURRENT_PROJECT_VERSION = 80;
DEVELOPMENT_TEAM = M8F9QH57A6;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Carthage/Build/iOS",
);
INFOPLIST_FILE = Example/Info.plist;
- LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ MARKETING_VERSION = 8.1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.buchetics.DataSourceExample;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE = "";
@@ -736,18 +733,25 @@
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ CURRENT_PROJECT_VERSION = 80;
DEVELOPMENT_TEAM = M8F9QH57A6;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Carthage/Build/iOS",
);
INFOPLIST_FILE = Example/Info.plist;
- LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ MARKETING_VERSION = 8.1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.buchetics.DataSourceExample;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE = "";
PROVISIONING_PROFILE_SPECIFIER = "";
- SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
+ SWIFT_COMPILATION_MODE = wholemodule;
+ SWIFT_OPTIMIZATION_LEVEL = "-O";
SWIFT_VERSION = 5.0;
};
name = Release;
@@ -756,10 +760,10 @@
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
- CODE_SIGN_IDENTITY = "iPhone Developer";
+ CODE_SIGN_IDENTITY = "";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 1;
+ CURRENT_PROJECT_VERSION = 80;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = M8F9QH57A6;
DYLIB_COMPATIBILITY_VERSION = 1;
@@ -771,7 +775,12 @@
);
INFOPLIST_FILE = DataSource/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
- LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ "@loader_path/Frameworks",
+ );
+ MARKETING_VERSION = 8.1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.buchetics.DataSource;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -788,10 +797,10 @@
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
- CODE_SIGN_IDENTITY = "iPhone Developer";
+ CODE_SIGN_IDENTITY = "";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 1;
+ CURRENT_PROJECT_VERSION = 80;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = M8F9QH57A6;
DYLIB_COMPATIBILITY_VERSION = 1;
@@ -803,12 +812,18 @@
);
INFOPLIST_FILE = DataSource/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
- LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ "@loader_path/Frameworks",
+ );
+ MARKETING_VERSION = 8.1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.buchetics.DataSource;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = YES;
- SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
+ SWIFT_COMPILATION_MODE = wholemodule;
+ SWIFT_OPTIMIZATION_LEVEL = "-O";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
@@ -828,8 +843,12 @@
"$(PROJECT_DIR)/Carthage/Build/iOS",
);
INFOPLIST_FILE = DataSourceTests/Info.plist;
- IPHONEOS_DEPLOYMENT_TARGET = 10.2;
- LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ "@loader_path/Frameworks",
+ );
PRODUCT_BUNDLE_IDENTIFIER = com.buchetics.DataSourceTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
@@ -850,11 +869,16 @@
"$(PROJECT_DIR)/Carthage/Build/iOS",
);
INFOPLIST_FILE = DataSourceTests/Info.plist;
- IPHONEOS_DEPLOYMENT_TARGET = 10.2;
- LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ "@loader_path/Frameworks",
+ );
PRODUCT_BUNDLE_IDENTIFIER = com.buchetics.DataSourceTests;
PRODUCT_NAME = "$(TARGET_NAME)";
- SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
+ SWIFT_COMPILATION_MODE = wholemodule;
+ SWIFT_OPTIMIZATION_LEVEL = "-O";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Example.app/Example";
};
@@ -900,6 +924,25 @@
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
+
+/* Begin XCRemoteSwiftPackageReference section */
+ 5FD722002500F36800835AA1 /* XCRemoteSwiftPackageReference "Differ" */ = {
+ isa = XCRemoteSwiftPackageReference;
+ repositoryURL = "https://github.com/tonyarnold/Differ";
+ requirement = {
+ kind = upToNextMajorVersion;
+ minimumVersion = 1.4.5;
+ };
+ };
+/* End XCRemoteSwiftPackageReference section */
+
+/* Begin XCSwiftPackageProductDependency section */
+ 5FD722012500F36800835AA1 /* Differ */ = {
+ isa = XCSwiftPackageProductDependency;
+ package = 5FD722002500F36800835AA1 /* XCRemoteSwiftPackageReference "Differ" */;
+ productName = Differ;
+ };
+/* End XCSwiftPackageProductDependency section */
};
rootObject = 395D14741B90610A00658680 /* Project object */;
}
diff --git a/DataSource.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/DataSource.xcodeproj/project.xcworkspace/contents.xcworkspacedata
index 106019c..919434a 100644
--- a/DataSource.xcodeproj/project.xcworkspace/contents.xcworkspacedata
+++ b/DataSource.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -2,6 +2,6 @@
+ location = "self:">
diff --git a/DataSource.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DataSource.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
new file mode 100644
index 0000000..4f1abe8
--- /dev/null
+++ b/DataSource.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
@@ -0,0 +1,16 @@
+{
+ "object": {
+ "pins": [
+ {
+ "package": "Differ",
+ "repositoryURL": "https://github.com/tonyarnold/Differ",
+ "state": {
+ "branch": null,
+ "revision": "4c3eb4d76ad5c14075829397a5741b0badb08dce",
+ "version": "1.4.5"
+ }
+ }
+ ]
+ },
+ "version": 1
+}
diff --git a/DataSource.xcodeproj/xcshareddata/xcschemes/DataSource.xcscheme b/DataSource.xcodeproj/xcshareddata/xcschemes/DataSource.xcscheme
index d0d4049..e074ccd 100644
--- a/DataSource.xcodeproj/xcshareddata/xcschemes/DataSource.xcscheme
+++ b/DataSource.xcodeproj/xcshareddata/xcschemes/DataSource.xcscheme
@@ -1,6 +1,6 @@
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ codeCoverageEnabled = "YES">
+
+
+
+
@@ -40,17 +49,6 @@
-
-
-
-
-
-
-
-
+
+
+
+
@@ -39,17 +48,6 @@
-
-
-
-
-
-
-
-
+
+
+
+
@@ -49,17 +58,6 @@
-
-
-
-
-
-
-
-
Void)? { get }
-
+
var canEditClosure: ((RowType, IndexPath) -> Bool)? { get }
var canMoveClosure: ((RowType, IndexPath) -> Bool)? { get }
var commitEditingClosure: ((RowType, UITableViewCell.EditingStyle, IndexPath) -> Void)? { get }
@@ -53,7 +51,7 @@ public protocol CellDescriptorType {
var editActionsClosure: ((RowType, IndexPath) -> [UITableViewRowAction]?)? { get }
var shouldIndentWhileEditingClosure: ((RowType, IndexPath) -> Bool)? { get }
var willBeginEditingClosure: ((RowType, IndexPath) -> Void)? { get }
-
+
var targetIndexPathForMoveClosure: ((RowType, (IndexPath, IndexPath)) -> IndexPath)? { get }
var indentationLevelClosure: ((RowType, IndexPath) -> Int)? { get }
var shouldShowMenuClosure: ((RowType, IndexPath) -> Bool)? { get }
@@ -73,10 +71,14 @@ public protocol CellDescriptorTypeiOS11: CellDescriptorType {
var trailingSwipeActionsClosure: ((RowType, IndexPath) -> UISwipeActionsConfiguration?)? { get }
}
-// MARK - CellDescriptor
+@available(iOS 13.0, *)
+public protocol CellDescriptorTypeiOS13: CellDescriptorType {
+ var configurationForMenuAtLocationClosure: ((RowType, IndexPath) -> UIContextMenuConfiguration?)? { get }
+}
+
+// MARK: - CellDescriptor
public class CellDescriptor- : CellDescriptorType {
-
public let rowIdentifier: String
public let cellIdentifier: String
public let bundle: Bundle?
@@ -104,7 +106,7 @@ public class CellDescriptor
- : CellDescriptorType {
}
return cell
}
-
+
// MARK: - UITableViewDataSource
// MARK: configure
@@ -112,7 +114,7 @@ public class CellDescriptor
- : CellDescriptorType {
public private(set) var configureClosure: ((RowType, UITableViewCell, IndexPath) -> Void)?
public func configure(_ closure: @escaping (Item, Cell, IndexPath) -> Void) -> CellDescriptor {
- configureClosure = { [unowned self] (row, cell, indexPath) in
+ configureClosure = { [unowned self] row, cell, indexPath in
closure(self.typedItem(row), self.typedCell(cell), indexPath)
}
return self
@@ -123,14 +125,14 @@ public class CellDescriptor
- : CellDescriptorType {
public private(set) var canEditClosure: ((RowType, IndexPath) -> Bool)?
public func canEdit(_ closure: @escaping (Item, IndexPath) -> Bool) -> CellDescriptor {
- canEditClosure = { [unowned self] (row, indexPath) in
+ canEditClosure = { [unowned self] row, indexPath in
closure(self.typedItem(row), indexPath)
}
return self
}
public func canEdit(_ closure: @escaping () -> Bool) -> CellDescriptor {
- canEditClosure = { (_, _) in
+ canEditClosure = { _, _ in
closure()
}
return self
@@ -141,14 +143,14 @@ public class CellDescriptor
- : CellDescriptorType {
public private(set) var canMoveClosure: ((RowType, IndexPath) -> Bool)?
public func canMove(_ closure: @escaping (Item, IndexPath) -> Bool) -> CellDescriptor {
- canMoveClosure = { [unowned self] (row, indexPath) in
+ canMoveClosure = { [unowned self] row, indexPath in
closure(self.typedItem(row), indexPath)
}
return self
}
public func canMove(_ closure: @escaping () -> Bool) -> CellDescriptor {
- canMoveClosure = { (_, _) in
+ canMoveClosure = { _, _ in
closure()
}
return self
@@ -159,15 +161,15 @@ public class CellDescriptor
- : CellDescriptorType {
public private(set) var heightClosure: ((RowType, IndexPath) -> CGFloat)?
public func height(_ closure: @escaping (Item, IndexPath) -> CGFloat) -> CellDescriptor {
- heightClosure = { [unowned self] (row, indexPath) in
- return closure(self.typedItem(row), indexPath)
+ heightClosure = { [unowned self] row, indexPath in
+ closure(self.typedItem(row), indexPath)
}
return self
}
public func height(_ closure: @escaping () -> CGFloat) -> CellDescriptor {
- heightClosure = { (_, _) in
- return closure()
+ heightClosure = { _, _ in
+ closure()
}
return self
}
@@ -177,15 +179,15 @@ public class CellDescriptor
- : CellDescriptorType {
public private(set) var estimatedHeightClosure: ((RowType, IndexPath) -> CGFloat)?
public func estimatedHeight(_ closure: @escaping (Item, IndexPath) -> CGFloat) -> CellDescriptor {
- estimatedHeightClosure = { [unowned self] (row, indexPath) in
- return closure(self.typedItem(row), indexPath)
+ estimatedHeightClosure = { [unowned self] row, indexPath in
+ closure(self.typedItem(row), indexPath)
}
return self
}
public func estimatedHeight(_ closure: @escaping () -> CGFloat) -> CellDescriptor {
- estimatedHeightClosure = { (_, _) in
- return closure()
+ estimatedHeightClosure = { _, _ in
+ closure()
}
return self
}
@@ -195,8 +197,8 @@ public class CellDescriptor
- : CellDescriptorType {
public private(set) var commitEditingClosure: ((RowType, UITableViewCell.EditingStyle, IndexPath) -> Void)?
public func commitEditing(_ closure: @escaping (Item, UITableViewCell.EditingStyle, IndexPath) -> Void) -> CellDescriptor {
- commitEditingClosure = { [unowned self] (row, editingStyle, indexPath) in
- return closure(self.typedItem(row), editingStyle, indexPath)
+ commitEditingClosure = { [unowned self] row, editingStyle, indexPath in
+ closure(self.typedItem(row), editingStyle, indexPath)
}
return self
}
@@ -206,8 +208,8 @@ public class CellDescriptor
- : CellDescriptorType {
public private(set) var moveRowClosure: ((RowType, (IndexPath, IndexPath)) -> Void)?
public func moveRow(_ closure: @escaping (Item, (IndexPath, IndexPath)) -> Void) -> CellDescriptor {
- moveRowClosure = { [unowned self] (row, indexPaths) in
- return closure(self.typedItem(row), indexPaths)
+ moveRowClosure = { [unowned self] row, indexPaths in
+ closure(self.typedItem(row), indexPaths)
}
return self
}
@@ -219,15 +221,15 @@ public class CellDescriptor
- : CellDescriptorType {
public private(set) var shouldHighlightClosure: ((RowType, IndexPath) -> Bool)?
public func shouldHighlight(_ closure: @escaping (Item, IndexPath) -> Bool) -> CellDescriptor {
- shouldHighlightClosure = { [unowned self] (row, indexPath) in
- return closure(self.typedItem(row), indexPath)
+ shouldHighlightClosure = { [unowned self] row, indexPath in
+ closure(self.typedItem(row), indexPath)
}
return self
}
public func shouldHighlight(_ closure: @escaping () -> Bool) -> CellDescriptor {
- shouldHighlightClosure = { (_, _) in
- return closure()
+ shouldHighlightClosure = { _, _ in
+ closure()
}
return self
}
@@ -237,15 +239,15 @@ public class CellDescriptor
- : CellDescriptorType {
public private(set) var didHighlightClosure: ((RowType, IndexPath) -> Void)?
public func didHighlight(_ closure: @escaping (Item, IndexPath) -> Void) -> CellDescriptor {
- didHighlightClosure = { [unowned self] (row, indexPath) in
- return closure(self.typedItem(row), indexPath)
+ didHighlightClosure = { [unowned self] row, indexPath in
+ closure(self.typedItem(row), indexPath)
}
return self
}
public func didHighlight(_ closure: @escaping () -> Void) -> CellDescriptor {
- didHighlightClosure = { (_, _) in
- return closure()
+ didHighlightClosure = { _, _ in
+ closure()
}
return self
}
@@ -255,15 +257,15 @@ public class CellDescriptor
- : CellDescriptorType {
public private(set) var didUnhighlightClosure: ((RowType, IndexPath) -> Void)?
public func didUnhighlight(_ closure: @escaping (Item, IndexPath) -> Void) -> CellDescriptor {
- didUnhighlightClosure = { [unowned self] (row, indexPath) in
- return closure(self.typedItem(row), indexPath)
+ didUnhighlightClosure = { [unowned self] row, indexPath in
+ closure(self.typedItem(row), indexPath)
}
return self
}
public func didUnhighlight(_ closure: @escaping () -> Void) -> CellDescriptor {
- didUnhighlightClosure = { (_, _) in
- return closure()
+ didUnhighlightClosure = { _, _ in
+ closure()
}
return self
}
@@ -273,15 +275,15 @@ public class CellDescriptor
- : CellDescriptorType {
public private(set) var willSelectClosure: ((RowType, IndexPath) -> IndexPath?)?
public func willSelect(_ closure: @escaping (Item, IndexPath) -> IndexPath?) -> CellDescriptor {
- willSelectClosure = { [unowned self] (row, indexPath) in
- return closure(self.typedItem(row), indexPath)
+ willSelectClosure = { [unowned self] row, indexPath in
+ closure(self.typedItem(row), indexPath)
}
return self
}
public func willSelect(_ closure: @escaping () -> IndexPath?) -> CellDescriptor {
- willSelectClosure = { (_, _) in
- return closure()
+ willSelectClosure = { _, _ in
+ closure()
}
return self
}
@@ -291,15 +293,15 @@ public class CellDescriptor
- : CellDescriptorType {
public private(set) var willDeselectClosure: ((RowType, IndexPath) -> IndexPath?)?
public func willDeselect(_ closure: @escaping (Item, IndexPath) -> IndexPath?) -> CellDescriptor {
- willDeselectClosure = { [unowned self] (row, indexPath) in
- return closure(self.typedItem(row), indexPath)
+ willDeselectClosure = { [unowned self] row, indexPath in
+ closure(self.typedItem(row), indexPath)
}
return self
}
public func willDeselect(_ closure: @escaping () -> IndexPath?) -> CellDescriptor {
- willDeselectClosure = { (_, _) in
- return closure()
+ willDeselectClosure = { _, _ in
+ closure()
}
return self
}
@@ -309,15 +311,15 @@ public class CellDescriptor
- : CellDescriptorType {
public private(set) var didSelectClosure: ((RowType, IndexPath) -> SelectionResult)?
public func didSelect(_ closure: @escaping (Item, IndexPath) -> SelectionResult) -> CellDescriptor {
- didSelectClosure = { [unowned self] (row, indexPath) in
- return closure(self.typedItem(row), indexPath)
+ didSelectClosure = { [unowned self] row, indexPath in
+ closure(self.typedItem(row), indexPath)
}
return self
}
public func didSelect(_ closure: @escaping () -> SelectionResult) -> CellDescriptor {
- didSelectClosure = { (_, _) in
- return closure()
+ didSelectClosure = { _, _ in
+ closure()
}
return self
}
@@ -327,15 +329,15 @@ public class CellDescriptor
- : CellDescriptorType {
public private(set) var didDeselectClosure: ((RowType, IndexPath) -> Void)?
public func didDeselect(_ closure: @escaping (Item, IndexPath) -> Void) -> CellDescriptor {
- didDeselectClosure = { [unowned self] (row, indexPath) in
- return closure(self.typedItem(row), indexPath)
+ didDeselectClosure = { [unowned self] row, indexPath in
+ closure(self.typedItem(row), indexPath)
}
return self
}
public func didDeselect(_ closure: @escaping () -> Void) -> CellDescriptor {
- didDeselectClosure = { (_, _) in
- return closure()
+ didDeselectClosure = { _, _ in
+ closure()
}
return self
}
@@ -345,8 +347,8 @@ public class CellDescriptor
- : CellDescriptorType {
public private(set) var willDisplayClosure: ((RowType, UITableViewCell, IndexPath) -> Void)?
public func willDisplay(_ closure: @escaping (Item, Cell, IndexPath) -> Void) -> CellDescriptor {
- willDisplayClosure = { [unowned self] (row, cell, indexPath) in
- return closure(self.typedItem(row), self.typedCell(cell), indexPath)
+ willDisplayClosure = { [unowned self] row, cell, indexPath in
+ closure(self.typedItem(row), self.typedCell(cell), indexPath)
}
return self
}
@@ -356,15 +358,15 @@ public class CellDescriptor
- : CellDescriptorType {
public private(set) var editingStyleClosure: ((RowType, IndexPath) -> UITableViewCell.EditingStyle)?
public func editingStyle(_ closure: @escaping (Item, IndexPath) -> UITableViewCell.EditingStyle) -> CellDescriptor {
- editingStyleClosure = { [unowned self] (row, indexPath) in
- return closure(self.typedItem(row), indexPath)
+ editingStyleClosure = { [unowned self] row, indexPath in
+ closure(self.typedItem(row), indexPath)
}
return self
}
public func editingStyle(_ closure: @escaping () -> UITableViewCell.EditingStyle) -> CellDescriptor {
- editingStyleClosure = { (_, _) in
- return closure()
+ editingStyleClosure = { _, _ in
+ closure()
}
return self
}
@@ -374,15 +376,15 @@ public class CellDescriptor
- : CellDescriptorType {
public private(set) var titleForDeleteConfirmationButtonClosure: ((RowType, IndexPath) -> String?)?
public func titleForDeleteConfirmationButton(_ closure: @escaping (Item, IndexPath) -> String?) -> CellDescriptor {
- titleForDeleteConfirmationButtonClosure = { [unowned self] (row, indexPath) in
- return closure(self.typedItem(row), indexPath)
+ titleForDeleteConfirmationButtonClosure = { [unowned self] row, indexPath in
+ closure(self.typedItem(row), indexPath)
}
return self
}
public func titleForDeleteConfirmationButton(_ closure: @escaping () -> String?) -> CellDescriptor {
- titleForDeleteConfirmationButtonClosure = { (_, _) in
- return closure()
+ titleForDeleteConfirmationButtonClosure = { _, _ in
+ closure()
}
return self
}
@@ -392,20 +394,24 @@ public class CellDescriptor
- : CellDescriptorType {
private var _leadingSwipeActionsClosure: ((RowType, IndexPath) -> Any?)?
private var _trailingSwipeActionsClosure: ((RowType, IndexPath) -> Any?)?
+ // MARK: contextMenu
+
+ public var _configurationForMenuAtLocationClosure: ((RowType, IndexPath) -> Any)?
+
// MARK: editActions
public private(set) var editActionsClosure: ((RowType, IndexPath) -> [UITableViewRowAction]?)?
public func editActions(_ closure: @escaping (Item, IndexPath) -> [UITableViewRowAction]?) -> CellDescriptor {
- editActionsClosure = { [unowned self] (row, indexPath) in
- return closure(self.typedItem(row), indexPath)
+ editActionsClosure = { [unowned self] row, indexPath in
+ closure(self.typedItem(row), indexPath)
}
return self
}
public func editActions(_ closure: @escaping () -> [UITableViewRowAction]?) -> CellDescriptor {
- editActionsClosure = { (_, _) in
- return closure()
+ editActionsClosure = { _, _ in
+ closure()
}
return self
}
@@ -415,15 +421,15 @@ public class CellDescriptor
- : CellDescriptorType {
public private(set) var shouldIndentWhileEditingClosure: ((RowType, IndexPath) -> Bool)?
public func shouldIndentWhileEditing(_ closure: @escaping (Item, IndexPath) -> Bool) -> CellDescriptor {
- shouldIndentWhileEditingClosure = { [unowned self] (row, indexPath) in
- return closure(self.typedItem(row), indexPath)
+ shouldIndentWhileEditingClosure = { [unowned self] row, indexPath in
+ closure(self.typedItem(row), indexPath)
}
return self
}
public func shouldIndentWhileEditing(_ closure: @escaping () -> Bool) -> CellDescriptor {
- shouldIndentWhileEditingClosure = { (_, _) in
- return closure()
+ shouldIndentWhileEditingClosure = { _, _ in
+ closure()
}
return self
}
@@ -433,14 +439,14 @@ public class CellDescriptor
- : CellDescriptorType {
public private(set) var willBeginEditingClosure: ((RowType, IndexPath) -> Void)?
public func willBeginEditing(_ closure: @escaping (Item, IndexPath) -> Void) -> CellDescriptor {
- willBeginEditingClosure = { [unowned self] (row, indexPath) in
+ willBeginEditingClosure = { [unowned self] row, indexPath in
closure(self.typedItem(row), indexPath)
}
return self
}
public func willBeginEditing(_ closure: @escaping () -> Void) -> CellDescriptor {
- willBeginEditingClosure = { (_, _) in
+ willBeginEditingClosure = { _, _ in
closure()
}
return self
@@ -451,7 +457,7 @@ public class CellDescriptor
- : CellDescriptorType {
public private(set) var targetIndexPathForMoveClosure: ((RowType, (IndexPath, IndexPath)) -> IndexPath)?
public func targetIndexPathForMove(_ closure: @escaping (Item, (IndexPath, IndexPath)) -> IndexPath) -> CellDescriptor {
- targetIndexPathForMoveClosure = { [unowned self] (row, indexPaths) in
+ targetIndexPathForMoveClosure = { [unowned self] row, indexPaths in
closure(self.typedItem(row), indexPaths)
}
return self
@@ -462,14 +468,14 @@ public class CellDescriptor
- : CellDescriptorType {
public private(set) var indentationLevelClosure: ((RowType, IndexPath) -> Int)?
public func indentationLevel(_ closure: @escaping (Item, IndexPath) -> Int) -> CellDescriptor {
- indentationLevelClosure = { [unowned self] (row, indexPath) in
+ indentationLevelClosure = { [unowned self] row, indexPath in
closure(self.typedItem(row), indexPath)
}
return self
}
public func indentationLevel(_ closure: @escaping () -> Int) -> CellDescriptor {
- indentationLevelClosure = { (_, _) in
+ indentationLevelClosure = { _, _ in
closure()
}
return self
@@ -480,14 +486,14 @@ public class CellDescriptor
- : CellDescriptorType {
public private(set) var shouldShowMenuClosure: ((RowType, IndexPath) -> Bool)?
public func shouldShowMenu(_ closure: @escaping (Item, IndexPath) -> Bool) -> CellDescriptor {
- shouldShowMenuClosure = { [unowned self] (row, indexPath) in
+ shouldShowMenuClosure = { [unowned self] row, indexPath in
closure(self.typedItem(row), indexPath)
}
return self
}
public func shouldShowMenu(_ closure: @escaping () -> Bool) -> CellDescriptor {
- shouldShowMenuClosure = { (_, _) in
+ shouldShowMenuClosure = { _, _ in
closure()
}
return self
@@ -498,14 +504,14 @@ public class CellDescriptor
- : CellDescriptorType {
public private(set) var canPerformActionClosure: ((RowType, Selector, Any?, IndexPath) -> Bool)?
public func canPerformAction(_ closure: @escaping (Item, Selector, Any?, IndexPath) -> Bool) -> CellDescriptor {
- canPerformActionClosure = { [unowned self] (row, selector, sender, indexPath) in
+ canPerformActionClosure = { [unowned self] row, selector, sender, indexPath in
closure(self.typedItem(row), selector, sender, indexPath)
}
return self
}
public func canPerformAction(_ closure: @escaping (Selector, Any?) -> Bool) -> CellDescriptor {
- canPerformActionClosure = { (_, selector, sender, _) in
+ canPerformActionClosure = { _, selector, sender, _ in
closure(selector, sender)
}
return self
@@ -516,14 +522,14 @@ public class CellDescriptor
- : CellDescriptorType {
public private(set) var performActionClosure: ((RowType, Selector, Any?, IndexPath) -> Void)?
public func performAction(_ closure: @escaping (Item, Selector, Any?, IndexPath) -> Void) -> CellDescriptor {
- performActionClosure = { [unowned self] (row, selector, sender, indexPath) in
+ performActionClosure = { [unowned self] row, selector, sender, indexPath in
closure(self.typedItem(row), selector, sender, indexPath)
}
return self
}
public func performAction(_ closure: @escaping (Selector, Any?) -> Void) -> CellDescriptor {
- performActionClosure = { (_, selector, sender, _) in
+ performActionClosure = { _, selector, sender, _ in
closure(selector, sender)
}
return self
@@ -534,14 +540,14 @@ public class CellDescriptor
- : CellDescriptorType {
public private(set) var canFocusClosure: ((RowType, IndexPath) -> Bool)?
public func canFocus(_ closure: @escaping (Item, IndexPath) -> Bool) -> CellDescriptor {
- canFocusClosure = { [unowned self] (row, indexPath) in
+ canFocusClosure = { [unowned self] row, indexPath in
closure(self.typedItem(row), indexPath)
}
return self
}
public func canFocus(_ closure: @escaping () -> Bool) -> CellDescriptor {
- canFocusClosure = { (_, _) in
+ canFocusClosure = { _, _ in
closure()
}
return self
@@ -554,14 +560,14 @@ public class CellDescriptor
- : CellDescriptorType {
public private(set) var isHiddenClosure: ((RowType, IndexPath) -> Bool)?
public func isHidden(_ closure: @escaping (Item, IndexPath) -> Bool) -> CellDescriptor {
- isHiddenClosure = { [unowned self] (row, indexPath) in
+ isHiddenClosure = { [unowned self] row, indexPath in
closure(self.typedItem(row), indexPath)
}
return self
}
public func isHidden(_ closure: @escaping () -> Bool) -> CellDescriptor {
- isHiddenClosure = { (_, _) in
+ isHiddenClosure = { _, _ in
closure()
}
return self
@@ -572,7 +578,7 @@ public class CellDescriptor
- : CellDescriptorType {
public private(set) var updateClosure: ((RowType, UITableViewCell, IndexPath) -> Void)?
public func update(_ closure: @escaping (Item, Cell, IndexPath) -> Void) -> CellDescriptor {
- updateClosure = { [unowned self] (row, cell, indexPath) in
+ updateClosure = { [unowned self] row, cell, indexPath in
closure(self.typedItem(row), self.typedCell(cell), indexPath)
}
return self
@@ -581,38 +587,37 @@ public class CellDescriptor
- : CellDescriptorType {
@available(iOS 11, *)
extension CellDescriptor: CellDescriptorTypeiOS11 {
-
public var leadingSwipeActionsClosure: ((RowType, IndexPath) -> UISwipeActionsConfiguration?)? {
- get {
- if _leadingSwipeActionsClosure == nil {
- return nil
- }
-
- return { [weak self] (rowType, indexPath) in
- return self?._leadingSwipeActionsClosure?(rowType, indexPath) as? UISwipeActionsConfiguration
- }
+ if _leadingSwipeActionsClosure == nil {
+ return nil
+ }
+
+ return { [weak self] rowType, indexPath in
+ self?._leadingSwipeActionsClosure?(rowType, indexPath) as? UISwipeActionsConfiguration
}
}
public var trailingSwipeActionsClosure: ((RowType, IndexPath) -> UISwipeActionsConfiguration?)? {
- get {
- if _trailingSwipeActionsClosure == nil {
- return nil
- }
-
- return { [weak self] (rowType, indexPath) in
- return self?._trailingSwipeActionsClosure?(rowType, indexPath) as? UISwipeActionsConfiguration
- }
+ if _trailingSwipeActionsClosure == nil {
+ return nil
+ }
+
+ return { [weak self] rowType, indexPath in
+ self?._trailingSwipeActionsClosure?(rowType, indexPath) as? UISwipeActionsConfiguration
}
}
- public func leadingSwipeAction(_ closure: @escaping ((RowType, IndexPath) -> UISwipeActionsConfiguration?)) -> CellDescriptor {
- _leadingSwipeActionsClosure = closure
+ public func leadingSwipeAction(_ closure: @escaping ((Item, IndexPath) -> UISwipeActionsConfiguration?)) -> CellDescriptor {
+ _leadingSwipeActionsClosure = { [unowned self] row, indexPath in
+ closure(self.typedItem(row), indexPath)
+ }
return self
}
- public func trailingSwipeAction(_ closure: @escaping ((RowType, IndexPath) -> UISwipeActionsConfiguration?)) -> CellDescriptor {
- _trailingSwipeActionsClosure = closure
+ public func trailingSwipeAction(_ closure: @escaping ((Item, IndexPath) -> UISwipeActionsConfiguration?)) -> CellDescriptor {
+ _trailingSwipeActionsClosure = { [unowned self] row, indexPath in
+ closure(self.typedItem(row), indexPath)
+ }
return self
}
@@ -624,3 +629,23 @@ extension CellDescriptor: CellDescriptorTypeiOS11 {
return _trailingSwipeActionsClosure != nil
}
}
+
+@available(iOS 13, *)
+extension CellDescriptor: CellDescriptorTypeiOS13 {
+ public var configurationForMenuAtLocationClosure: ((RowType, IndexPath) -> UIContextMenuConfiguration?)? {
+ if _configurationForMenuAtLocationClosure == nil {
+ return nil
+ }
+
+ return { [weak self] rowType, indexPath in
+ self?._configurationForMenuAtLocationClosure?(rowType, indexPath) as? UIContextMenuConfiguration
+ }
+ }
+
+ public func configurationForMenuAtLocation(_ closure: @escaping ((Item, IndexPath) -> UIContextMenuConfiguration)) -> CellDescriptor {
+ _configurationForMenuAtLocationClosure = { [unowned self] row, indexPath in
+ closure(self.typedItem(row), indexPath)
+ }
+ return self
+ }
+}
diff --git a/DataSource/DataSource+UITableViewDataSource.swift b/DataSource/DataSource+UITableViewDataSource.swift
index 3fa848a..ae7e8fb 100644
--- a/DataSource/DataSource+UITableViewDataSource.swift
+++ b/DataSource/DataSource+UITableViewDataSource.swift
@@ -1,44 +1,46 @@
-//
-// 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) && bundle.path(forResource: cellIdentifier, ofType: "nib") != nil {
- tableView.registerNib(cellIdentifier, bundle: bundle)
- reuseIdentifiers.insert(cellIdentifier)
+
+ if registerNibs, !reuseIdentifiers.contains(cellIdentifier) {
+ if bundle.path(forResource: cellIdentifier, ofType: "nib") != nil {
+ tableView.registerNib(cellIdentifier, bundle: bundle)
+ reuseIdentifiers.insert(cellIdentifier)
+ } else if cellDescriptor.cellClass is AutoRegisterCell.Type {
+ tableView.register(cellDescriptor.cellClass, forCellReuseIdentifier: cellIdentifier)
+ 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)
@@ -48,13 +50,17 @@ 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
@@ -62,16 +68,20 @@ extension DataSource: UITableViewDataSource {
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
@@ -79,70 +89,86 @@ extension DataSource: UITableViewDataSource {
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)
}
}
diff --git a/DataSource/DataSource+UITableViewDelegate.swift b/DataSource/DataSource+UITableViewDelegate.swift
index 9a743ad..811a815 100644
--- a/DataSource/DataSource+UITableViewDelegate.swift
+++ b/DataSource/DataSource+UITableViewDelegate.swift
@@ -1,82 +1,96 @@
-//
-// DataSource+UITableViewDelegate.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: UITableViewDelegate {
-
// MARK: Highlighting
-
+
public func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool {
let cellDescriptor = self.cellDescriptor(at: indexPath)
-
- if let closure = cellDescriptor.shouldHighlightClosure ?? shouldHighlight {
- return closure(visibleRow(at: indexPath), indexPath)
+
+ if let closure = cellDescriptor?.shouldHighlightClosure ?? shouldHighlight {
+ guard let visibleRow = visibleRow(at: indexPath) else {
+ return false
+ }
+
+ return closure(visibleRow, indexPath)
}
-
+
return fallbackDelegate?.tableView?(tableView, shouldHighlightRowAt: indexPath)
?? true
}
-
+
public func tableView(_ tableView: UITableView, didHighlightRowAt indexPath: IndexPath) {
let cellDescriptor = self.cellDescriptor(at: indexPath)
-
- if let closure = cellDescriptor.didHighlightClosure ?? didHighlight {
- closure(visibleRow(at: indexPath), indexPath)
+
+ if let closure = cellDescriptor?.didHighlightClosure ?? didHighlight {
+ guard let visibleRow = visibleRow(at: indexPath) else {
+ return
+ }
+
+ closure(visibleRow, indexPath)
return
}
-
+
fallbackDelegate?.tableView?(tableView, didHighlightRowAt: indexPath)
}
-
+
public func tableView(_ tableView: UITableView, didUnhighlightRowAt indexPath: IndexPath) {
let cellDescriptor = self.cellDescriptor(at: indexPath)
-
- if let closure = cellDescriptor.didUnhighlightClosure ?? didUnhighlight {
- closure(visibleRow(at: indexPath), indexPath)
+
+ if let closure = cellDescriptor?.didUnhighlightClosure ?? didUnhighlight {
+ guard let visibleRow = visibleRow(at: indexPath) else {
+ return
+ }
+
+ closure(visibleRow, indexPath)
return
}
fallbackDelegate?.tableView?(tableView, didUnhighlightRowAt: indexPath)
}
-
+
// MARK: Selection
-
+
public func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
let cellDescriptor = self.cellDescriptor(at: indexPath)
-
- if let closure = cellDescriptor.willSelectClosure ?? willSelect {
- return closure(visibleRow(at: indexPath), indexPath)
+
+ if let closure = cellDescriptor?.willSelectClosure ?? willSelect {
+ guard let visibleRow = visibleRow(at: indexPath) else {
+ return nil
+ }
+
+ return closure(visibleRow, indexPath)
}
-
+
return fallbackDelegate?.tableView?(tableView, willSelectRowAt: indexPath)
?? indexPath
}
-
+
public func tableView(_ tableView: UITableView, willDeselectRowAt indexPath: IndexPath) -> IndexPath? {
let cellDescriptor = self.cellDescriptor(at: indexPath)
-
- if let closure = cellDescriptor.willDeselectClosure ?? willDeselect {
- return closure(visibleRow(at: indexPath), indexPath)
+
+ if let closure = cellDescriptor?.willDeselectClosure ?? willDeselect {
+ guard let visibleRow = visibleRow(at: indexPath) else {
+ return nil
+ }
+
+ return closure(visibleRow, indexPath)
}
-
+
return fallbackDelegate?.tableView?(tableView, willDeselectRowAt: indexPath)
?? indexPath
}
-
+
public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cellDescriptor = self.cellDescriptor(at: indexPath)
-
-
- if let closure = cellDescriptor.didSelectClosure ?? didSelect {
- let selectionResult = closure(visibleRow(at: indexPath), indexPath)
+
+ if let closure = cellDescriptor?.didSelectClosure ?? didSelect {
+ guard let visibleRow = visibleRow(at: indexPath) else {
+ return
+ }
+ let selectionResult = closure(visibleRow, indexPath)
+
switch selectionResult {
case .deselect:
if let selectedIndexPath = tableView.indexPathForSelectedRow {
@@ -89,26 +103,34 @@ extension DataSource: UITableViewDelegate {
fallbackDelegate?.tableView?(tableView, didSelectRowAt: indexPath)
}
}
-
+
public func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
let cellDescriptor = self.cellDescriptor(at: indexPath)
-
- if let closure = cellDescriptor.didDeselectClosure ?? didDeselect {
- closure(visibleRow(at: indexPath), indexPath)
+
+ if let closure = cellDescriptor?.didDeselectClosure ?? didDeselect {
+ guard let visibleRow = visibleRow(at: indexPath) else {
+ return
+ }
+
+ closure(visibleRow, indexPath)
return
}
-
+
fallbackDelegate?.tableView?(tableView, didDeselectRowAt: indexPath)
}
-
+
// MARK: Header & Footer
-
- public func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
+
+ public func tableView(_: UITableView, viewForHeaderInSection section: Int) -> UIView? {
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 .view(let view):
return view
@@ -116,16 +138,20 @@ extension DataSource: UITableViewDelegate {
return nil
}
}
-
+
return nil
}
-
- public func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
+
+ public func tableView(_: UITableView, viewForFooterInSection section: Int) -> UIView? {
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 .view(let view):
return view
@@ -133,21 +159,25 @@ extension DataSource: UITableViewDelegate {
return nil
}
}
-
+
return nil
}
-
+
// MARK: Height
-
+
// NOTE: estimated section header and footer heights are not supported
-
+
public func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let cellDescriptor = self.cellDescriptor(at: indexPath)
-
- if let closure = cellDescriptor.heightClosure ?? height {
- return closure(visibleRow(at: indexPath), indexPath)
+
+ if let closure = cellDescriptor?.heightClosure ?? height {
+ guard let visibleRow = visibleRow(at: indexPath) else {
+ return tableView.rowHeight
+ }
+
+ return closure(visibleRow, indexPath)
}
-
+
return fallbackDelegate?.tableView?(tableView, heightForRowAt: indexPath)
?? tableView.rowHeight
}
@@ -155,54 +185,66 @@ extension DataSource: UITableViewDelegate {
public func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
let index = indexPath.section
let section = visibleSection(at: index)
-
- // Do not get the CellDescriptor if we are dealing with a LazySection because it would instaniate all the rows,
- // i.e. estimatedHeightClosure will not be called for LazySections. Instead, use the estimatedHeight on the
+
+ // Do not get the CellDescriptor if we are dealing with a LazySection because it would instantiate all the rows,
+ // i.e. estimatedHeightClosure will not be called for LazySections. Instead, use the estimatedHeight on the
// DataSource, the fallback delegate or a constant.
-
+
if !(section is LazySectionType) {
let cellDescriptor = self.cellDescriptor(at: indexPath)
-
- if let closure = cellDescriptor.estimatedHeightClosure {
- return closure(visibleRow(at: indexPath), indexPath)
+
+ if let closure = cellDescriptor?.estimatedHeightClosure {
+ guard let visibleRow = visibleRow(at: indexPath) else {
+ return UITableView.automaticDimension
+ }
+
+ return closure(visibleRow, indexPath)
}
}
-
+
if let closure = estimatedHeight {
return closure(indexPath)
}
-
+
if let result = fallbackDelegate?.tableView?(tableView, estimatedHeightForRowAt: indexPath) {
return result
}
-
+
if tableView.estimatedRowHeight > 0 {
return tableView.estimatedRowHeight
}
-
+
return UITableView.automaticDimension
}
-
+
public func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
let sectionDescriptor = self.sectionDescriptor(at: section)
if let closure = sectionDescriptor?.headerHeightClosure ?? sectionHeaderHeight {
- return closure(visibleSection(at: section), section).floatValue(for: tableView.style)
+ guard let visibleSection = visibleSection(at: section) else {
+ return UITableView.automaticDimension
+ }
+
+ return closure(visibleSection, section).floatValue(for: tableView.style)
}
-
- if let result = fallbackDelegate?.tableView?(tableView, heightForHeaderInSection: section) {
+
+ if let result = fallbackDelegate?.tableView?(tableView, heightForHeaderInSection: section) {
return result
}
-
+
if let headerClosure = sectionDescriptor?.headerClosure ?? sectionHeader {
- let header = headerClosure(visibleSection(at: section), section)
+ guard let visibleSection = visibleSection(at: section) else {
+ return 0.0
+ }
+ let header = headerClosure(visibleSection, section)
+
switch header {
case .title:
return UITableView.automaticDimension
case .view(let view):
let height = view.bounds.height
-
+
if height == 0 {
return tableView.sectionHeaderHeight > 0 ? tableView.sectionHeaderHeight : UITableView.automaticDimension
} else {
@@ -212,30 +254,38 @@ extension DataSource: UITableViewDelegate {
return 0.0
}
}
-
+
return 0.0
}
-
+
public func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
let sectionDescriptor = self.sectionDescriptor(at: section)
-
+
if let closure = sectionDescriptor?.footerHeightClosure ?? sectionFooterHeight {
- return closure(visibleSection(at: section), section).floatValue(for: tableView.style)
+ guard let visibleSection = visibleSection(at: section) else {
+ return UITableView.automaticDimension
+ }
+
+ return closure(visibleSection, section).floatValue(for: tableView.style)
}
-
+
if let result = fallbackDelegate?.tableView?(tableView, heightForFooterInSection: section) {
return result
}
-
+
if let footerClosure = sectionDescriptor?.footerClosure ?? sectionFooter {
- let footer = footerClosure(visibleSection(at: section), section)
+ guard let visibleSection = visibleSection(at: section) else {
+ return 0.0
+ }
+ let footer = footerClosure(visibleSection, section)
+
switch footer {
case .title:
return UITableView.automaticDimension
case .view(let view):
let height = view.bounds.height
-
+
if height == 0 {
return tableView.sectionFooterHeight > 0 ? tableView.sectionFooterHeight : UITableView.automaticDimension
} else {
@@ -245,247 +295,345 @@ extension DataSource: UITableViewDelegate {
return 0.0
}
}
-
+
return 0.0
}
-
+
// MARK: Display customization
-
+
public func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
let cellDescriptor = self.cellDescriptor(at: indexPath)
-
- if let closure = cellDescriptor.willDisplayClosure ?? willDisplay {
- closure(visibleRow(at: indexPath), cell, indexPath)
+
+ if let closure = cellDescriptor?.willDisplayClosure ?? willDisplay {
+ guard let visibleRow = visibleRow(at: indexPath) else {
+ return
+ }
+
+ closure(visibleRow, cell, indexPath)
return
}
-
- fallbackDelegate?.tableView?(tableView, willDisplay:cell, forRowAt:indexPath)
+
+ fallbackDelegate?.tableView?(tableView, willDisplay: cell, forRowAt: indexPath)
}
-
+
public func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
let sectionDescriptor = self.sectionDescriptor(at: section)
-
+
if let closure = sectionDescriptor?.willDisplayHeaderClosure ?? willDisplaySectionHeader {
- closure(visibleSection(at: section), view, section)
+ guard let visibleSection = visibleSection(at: section) else {
+ return
+ }
+
+ closure(visibleSection, view, section)
return
}
-
- fallbackDelegate?.tableView?(tableView, willDisplayHeaderView:view, forSection:section)
+
+ fallbackDelegate?.tableView?(tableView, willDisplayHeaderView: view, forSection: section)
}
-
+
public func tableView(_ tableView: UITableView, willDisplayFooterView view: UIView, forSection section: Int) {
let sectionDescriptor = self.sectionDescriptor(at: section)
-
+
if let closure = sectionDescriptor?.willDisplayFooterClosure ?? willDisplaySectionFooter {
- closure(visibleSection(at: section), view, section)
+ guard let visibleSection = visibleSection(at: section) else {
+ return
+ }
+
+ closure(visibleSection, view, section)
return
}
-
- fallbackDelegate?.tableView?(tableView, willDisplayFooterView:view, forSection:section)
+
+ fallbackDelegate?.tableView?(tableView, willDisplayFooterView: view, forSection: section)
}
-
+
// the didEnd delegate methods are only supported on a "fallback" level as we may not have the row or section
// available at this point anymore and we don't want to keep a reference to old data
-
+
public func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
if let closure = didEndDisplaying {
closure(cell, indexPath)
return
}
-
- fallbackDelegate?.tableView?(tableView, didEndDisplaying:cell, forRowAt:indexPath)
+
+ fallbackDelegate?.tableView?(tableView, didEndDisplaying: cell, forRowAt: indexPath)
}
-
+
public func tableView(_ tableView: UITableView, didEndDisplayingHeaderView view: UIView, forSection section: Int) {
if let closure = didEndDisplayingSectionHeader {
closure(view, section)
return
}
-
- fallbackDelegate?.tableView?(tableView, didEndDisplayingHeaderView:view, forSection:section)
+
+ fallbackDelegate?.tableView?(tableView, didEndDisplayingHeaderView: view, forSection: section)
}
-
+
public func tableView(_ tableView: UITableView, didEndDisplayingFooterView view: UIView, forSection section: Int) {
if let closure = didEndDisplayingSectionFooter {
closure(view, section)
return
}
-
- fallbackDelegate?.tableView?(tableView, didEndDisplayingFooterView:view, forSection:section)
+
+ fallbackDelegate?.tableView?(tableView, didEndDisplayingFooterView: view, forSection: section)
}
-
+
// MARK: Editing
-
+
public func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle {
let cellDescriptor = self.cellDescriptor(at: indexPath)
-
- if let closure = cellDescriptor.editingStyleClosure ?? editingStyle {
- return closure(visibleRow(at: indexPath), indexPath)
+
+ if let closure = cellDescriptor?.editingStyleClosure ?? editingStyle {
+ guard let visibleRow = visibleRow(at: indexPath) else {
+ return .none
+ }
+
+ return closure(visibleRow, indexPath)
}
-
- if let result = fallbackDelegate?.tableView?(tableView, editingStyleForRowAt:indexPath) {
+
+ if let result = fallbackDelegate?.tableView?(tableView, editingStyleForRowAt: indexPath) {
return result
}
-
+
if self.tableView(tableView, canEditRowAt: indexPath) {
return .delete
}
-
+
return .none
}
-
+
public func tableView(_ tableView: UITableView, titleForDeleteConfirmationButtonForRowAt indexPath: IndexPath) -> String? {
let cellDescriptor = self.cellDescriptor(at: indexPath)
-
- if let closure = cellDescriptor.titleForDeleteConfirmationButtonClosure ?? titleForDeleteConfirmationButton {
- return closure(visibleRow(at: indexPath), indexPath)
+
+ if let closure = cellDescriptor?.titleForDeleteConfirmationButtonClosure ?? titleForDeleteConfirmationButton {
+ guard let visibleRow = visibleRow(at: indexPath) else {
+ return nil
+ }
+
+ return closure(visibleRow, indexPath)
}
-
- return fallbackDelegate?.tableView?(tableView, titleForDeleteConfirmationButtonForRowAt:indexPath)
+
+ return fallbackDelegate?.tableView?(tableView, titleForDeleteConfirmationButtonForRowAt: indexPath)
}
-
+
public func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
- let cellDescriptor = self.cellDescriptor(at: indexPath)
+ guard !indexPath.isEmpty else { return [] }
- if let closure = cellDescriptor.editActionsClosure ?? editActions {
- return closure(visibleRow(at: indexPath), indexPath)
+ let cellDescriptor = self.cellDescriptor(at: indexPath)
+
+ if let closure = cellDescriptor?.editActionsClosure ?? editActions {
+ guard let visibleRow = visibleRow(at: indexPath) else {
+ return nil
+ }
+
+ return closure(visibleRow, indexPath)
}
-
- return fallbackDelegate?.tableView?(tableView, editActionsForRowAt:indexPath)
+
+ return fallbackDelegate?.tableView?(tableView, editActionsForRowAt: indexPath)
}
-
+
public func tableView(_ tableView: UITableView, shouldIndentWhileEditingRowAt indexPath: IndexPath) -> Bool {
let cellDescriptor = self.cellDescriptor(at: indexPath)
-
- if let closure = cellDescriptor.shouldIndentWhileEditingClosure ?? shouldIndentWhileEditing {
- return closure(visibleRow(at: indexPath), indexPath)
+
+ if let closure = cellDescriptor?.shouldIndentWhileEditingClosure ?? shouldIndentWhileEditing {
+ guard let visibleRow = visibleRow(at: indexPath) else {
+ return true
+ }
+
+ return closure(visibleRow, indexPath)
}
-
- return fallbackDelegate?.tableView?(tableView, shouldIndentWhileEditingRowAt:indexPath)
+
+ return fallbackDelegate?.tableView?(tableView, shouldIndentWhileEditingRowAt: indexPath)
?? true
}
-
+
public func tableView(_ tableView: UITableView, willBeginEditingRowAt indexPath: IndexPath) {
let cellDescriptor = self.cellDescriptor(at: indexPath)
-
- if let closure = cellDescriptor.willBeginEditingClosure ?? willBeginEditing {
- closure(visibleRow(at: indexPath), indexPath)
+
+ if let closure = cellDescriptor?.willBeginEditingClosure ?? willBeginEditing {
+ guard let visibleRow = visibleRow(at: indexPath) else {
+ return
+ }
+
+ closure(visibleRow, indexPath)
return
}
-
- fallbackDelegate?.tableView?(tableView, willBeginEditingRowAt:indexPath)
+
+ fallbackDelegate?.tableView?(tableView, willBeginEditingRowAt: indexPath)
}
-
+
public func tableView(_ tableView: UITableView, didEndEditingRowAt indexPath: IndexPath?) {
if let closure = didEndEditing {
closure(indexPath)
return
}
-
- fallbackDelegate?.tableView?(tableView, didEndEditingRowAt:indexPath)
+
+ fallbackDelegate?.tableView?(tableView, didEndEditingRowAt: indexPath)
}
// MARK: Moving & Reordering
-
+
public func tableView(_ tableView: UITableView, targetIndexPathForMoveFromRowAt sourceIndexPath: IndexPath, toProposedIndexPath proposedDestinationIndexPath: IndexPath) -> IndexPath {
let cellDescriptor = self.cellDescriptor(at: sourceIndexPath)
-
- if let closure = cellDescriptor.targetIndexPathForMoveClosure ?? targetIndexPathForMove {
- return closure(visibleRow(at: sourceIndexPath), (sourceIndexPath, proposedDestinationIndexPath))
+
+ if let closure = cellDescriptor?.targetIndexPathForMoveClosure ?? targetIndexPathForMove {
+ guard let visibleRow = visibleRow(at: sourceIndexPath) else {
+ return proposedDestinationIndexPath
+ }
+
+ return closure(visibleRow, (sourceIndexPath, proposedDestinationIndexPath))
}
-
- return fallbackDelegate?.tableView?(tableView, targetIndexPathForMoveFromRowAt:sourceIndexPath, toProposedIndexPath: proposedDestinationIndexPath)
+
+ return fallbackDelegate?.tableView?(tableView, targetIndexPathForMoveFromRowAt: sourceIndexPath, toProposedIndexPath: proposedDestinationIndexPath)
?? proposedDestinationIndexPath
}
-
-
+
// MARK: Indentation
-
+
public func tableView(_ tableView: UITableView, indentationLevelForRowAt indexPath: IndexPath) -> Int {
let cellDescriptor = self.cellDescriptor(at: indexPath)
-
- if let closure = cellDescriptor.indentationLevelClosure ?? indentationLevel {
- return closure(visibleRow(at: indexPath), indexPath)
+
+ if let closure = cellDescriptor?.indentationLevelClosure ?? indentationLevel {
+ guard let visibleRow = visibleRow(at: indexPath) else {
+ return 0
+ }
+
+ return closure(visibleRow, indexPath)
}
-
+
return fallbackDelegate?.tableView?(tableView, indentationLevelForRowAt: indexPath)
?? 0
}
-
+
// MARK: Copy & Paste
-
+
public func tableView(_ tableView: UITableView, shouldShowMenuForRowAt indexPath: IndexPath) -> Bool {
let cellDescriptor = self.cellDescriptor(at: indexPath)
-
- if let closure = cellDescriptor.shouldShowMenuClosure ?? shouldShowMenu {
- return closure(visibleRow(at: indexPath), indexPath)
+
+ if let closure = cellDescriptor?.shouldShowMenuClosure ?? shouldShowMenu {
+ guard let visibleRow = visibleRow(at: indexPath) else {
+ return false
+ }
+
+ return closure(visibleRow, indexPath)
}
-
+
return fallbackDelegate?.tableView?(tableView, shouldShowMenuForRowAt: indexPath)
?? false
}
-
+
public func tableView(_ tableView: UITableView, canPerformAction action: Selector, forRowAt indexPath: IndexPath, withSender sender: Any?) -> Bool {
let cellDescriptor = self.cellDescriptor(at: indexPath)
-
- if let closure = cellDescriptor.canPerformActionClosure ?? canPerformAction {
- return closure(visibleRow(at: indexPath), action, sender, indexPath)
+
+ if let closure = cellDescriptor?.canPerformActionClosure ?? canPerformAction {
+ guard let visibleRow = visibleRow(at: indexPath) else {
+ return false
+ }
+
+ return closure(visibleRow, action, sender, indexPath)
}
-
+
return fallbackDelegate?.tableView?(tableView, canPerformAction: action, forRowAt: indexPath, withSender: sender)
?? false
}
-
+
public func tableView(_ tableView: UITableView, performAction action: Selector, forRowAt indexPath: IndexPath, withSender sender: Any?) {
let cellDescriptor = self.cellDescriptor(at: indexPath)
-
- if let closure = cellDescriptor.performActionClosure ?? performAction {
- closure(visibleRow(at: indexPath), action, sender, indexPath)
+
+ if let closure = cellDescriptor?.performActionClosure ?? performAction {
+ guard let visibleRow = visibleRow(at: indexPath) else {
+ return
+ }
+
+ closure(visibleRow, action, sender, indexPath)
return
}
-
+
fallbackDelegate?.tableView?(tableView, performAction: action, forRowAt: indexPath, withSender: sender)
}
-
+
// MARK: Focus
-
+
public func tableView(_ tableView: UITableView, canFocusRowAt indexPath: IndexPath) -> Bool {
- return fallbackDelegate?.tableView?(tableView, canFocusRowAt:indexPath)
+ return fallbackDelegate?.tableView?(tableView, canFocusRowAt: indexPath)
?? true
}
-
+
public func tableView(_ tableView: UITableView, shouldUpdateFocusIn context: UITableViewFocusUpdateContext) -> Bool {
- return fallbackDelegate?.tableView?(tableView, shouldUpdateFocusIn:context)
+ return fallbackDelegate?.tableView?(tableView, shouldUpdateFocusIn: context)
?? true
}
-
+
public func tableView(_ tableView: UITableView, didUpdateFocusIn context: UITableViewFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) {
- fallbackDelegate?.tableView?(tableView, didUpdateFocusIn:context, with:coordinator)
+ fallbackDelegate?.tableView?(tableView, didUpdateFocusIn: context, with: coordinator)
}
-
+
public func indexPathForPreferredFocusedView(in tableView: UITableView) -> IndexPath? {
return fallbackDelegate?.indexPathForPreferredFocusedView?(in: tableView)
}
-
}
@available(iOS 11,*)
-extension DataSource {
- public func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
+public extension DataSource {
+ func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
+ if indexPath.indices.count != 2 {
+ // Problem: "Crash in IndexPath.section.getter"
+ // When an indexPath has not exactly two indices, the getter for
+ // `section` traps, causing crashes. This should not happen, but
+ // sometimes it does anyways.
+ return nil
+ }
let cellDescriptor = self.cellDescriptor(at: indexPath) as? CellDescriptorTypeiOS11
if let closure = cellDescriptor?.trailingSwipeActionsClosure {
- return closure(row(at: indexPath), indexPath)
+ guard let visibleRow = visibleRow(at: indexPath) else {
+ return nil
+ }
+
+ return closure(visibleRow, indexPath)
} else {
return fallbackDelegate?.tableView?(tableView, trailingSwipeActionsConfigurationForRowAt: indexPath)
}
}
-
- public func tableView(_ tableView: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
+
+ func tableView(_ tableView: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
+ if indexPath.indices.count != 2 {
+ // Problem: "Crash in IndexPath.section.getter"
+ // When an indexPath has not exactly two indices, the getter for
+ // `section` traps, causing crashes. This should not happen, but
+ // sometimes it does anyways.
+ return nil
+ }
let cellDescriptor = self.cellDescriptor(at: indexPath) as? CellDescriptorTypeiOS11
if let closure = cellDescriptor?.leadingSwipeActionsClosure {
- return closure(row(at: indexPath), indexPath)
+ guard let visibleRow = visibleRow(at: indexPath) else {
+ return nil
+ }
+
+ return closure(visibleRow, indexPath)
} else {
return fallbackDelegate?.tableView?(tableView, leadingSwipeActionsConfigurationForRowAt: indexPath)
}
}
}
+
+@available(iOS 13,*)
+public extension DataSource {
+ func tableView(_ tableView: UITableView, contextMenuConfigurationForRowAt indexPath: IndexPath, point _: CGPoint) -> UIContextMenuConfiguration? {
+ if indexPath.indices.count != 2 {
+ // Problem: "Crash in IndexPath.section.getter"
+ // When an indexPath has not exactly two indices, the getter for
+ // `section` traps, causing crashes. This should not happen, but
+ // sometimes it does anyways.
+ return nil
+ }
+ let cellDescriptor = self.cellDescriptor(at: indexPath) as? CellDescriptorTypeiOS13
+
+ if let closure = cellDescriptor?.configurationForMenuAtLocationClosure {
+ guard let visibleRow = visibleRow(at: indexPath) else {
+ return nil
+ }
+
+ return closure(visibleRow, indexPath)
+ } else {
+ return fallbackDelegate?.tableView?(tableView, contextMenuConfigurationForRowAt: indexPath, point: CGPoint(x: 0, y: 0))
+ }
+ }
+}
diff --git a/DataSource/DataSource.swift b/DataSource/DataSource.swift
index 7b8d2ce..1d0d454 100644
--- a/DataSource/DataSource.swift
+++ b/DataSource/DataSource.swift
@@ -1,99 +1,93 @@
-//
-// DataSource.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
public class DataSource: NSObject {
-
public var sections: [SectionType] = []
public internal(set) var visibleSections: [SectionType] = []
-
+
// MARK: UITableViewDataSource
-
- public var configure: ((RowType, UITableViewCell, IndexPath) -> Void)? = nil
- public var canEdit: ((RowType, IndexPath) -> Bool)? = nil
- public var canMove: ((RowType, IndexPath) -> Bool)? = nil
- public var sectionIndexTitles: (() -> [String]?)? = nil
- public var sectionForSectionIndex: ((String, Int) -> Int)? = nil
- public var commitEditing: ((RowType, UITableViewCell.EditingStyle, IndexPath) -> Void)? = nil
- public var moveRow: ((RowType, (IndexPath, IndexPath)) -> Void)? = nil
-
- public var fallbackDataSource: UITableViewDataSource? = nil
-
+
+ public var configure: ((RowType, UITableViewCell, IndexPath) -> Void)?
+ public var canEdit: ((RowType, IndexPath) -> Bool)?
+ public var canMove: ((RowType, IndexPath) -> Bool)?
+ public var sectionIndexTitles: (() -> [String]?)?
+ public var sectionForSectionIndex: ((String, Int) -> Int)?
+ public var commitEditing: ((RowType, UITableViewCell.EditingStyle, IndexPath) -> Void)?
+ public var moveRow: ((RowType, (IndexPath, IndexPath)) -> Void)?
+
+ public var fallbackDataSource: UITableViewDataSource?
+
// MARK: UITableViewDelegate
-
- public var height: ((RowType, IndexPath) -> CGFloat)? = nil
-
+
+ public var height: ((RowType, IndexPath) -> CGFloat)?
+
// no RowType parameter for estimatedHeight because we do not want to potentially instantiate
// a LazyRow just to get the height estimate
- public var estimatedHeight: ((IndexPath) -> CGFloat)? = nil
-
- public var shouldHighlight: ((RowType, IndexPath) -> Bool)? = nil
- public var didHighlight: ((RowType, IndexPath) -> Void)? = nil
- public var didUnhighlight: ((RowType, IndexPath) -> Void)? = nil
-
- public var willSelect: ((RowType, IndexPath) -> IndexPath?)? = nil
- public var willDeselect: ((RowType, IndexPath) -> IndexPath?)? = nil
- public var didSelect: ((RowType, IndexPath) -> SelectionResult)? = nil
- public var didDeselect: ((RowType, IndexPath) -> Void)? = nil
-
- public var willDisplay: ((RowType, UITableViewCell, IndexPath) -> Void)? = nil
- public var didEndDisplaying: ((UITableViewCell, IndexPath) -> Void)? = nil
-
- public var editingStyle: ((RowType, IndexPath) -> UITableViewCell.EditingStyle)? = nil
- public var titleForDeleteConfirmationButton: ((RowType, IndexPath) -> String?)? = nil
- public var editActions: ((RowType, IndexPath) -> [UITableViewRowAction]?)? = nil
- public var shouldIndentWhileEditing: ((RowType, IndexPath) -> Bool)? = nil
- public var willBeginEditing: ((RowType, IndexPath) -> Void)? = nil
- public var didEndEditing: ((IndexPath?) -> Void)? = nil
-
- public var sectionHeader: ((SectionType, Int) -> HeaderFooter)? = nil
- public var sectionFooter: ((SectionType, Int) -> HeaderFooter)? = nil
-
- public var sectionHeaderHeight: ((SectionType, Int) -> SectionHeight)? = nil
- public var sectionFooterHeight: ((SectionType, Int) -> SectionHeight)? = nil
-
- public var willDisplaySectionHeader: ((SectionType, UIView, Int) -> Void)? = nil
- public var willDisplaySectionFooter: ((SectionType, UIView, Int) -> Void)? = nil
-
- public var didEndDisplayingSectionHeader: ((UIView, Int) -> Void)? = nil
- public var didEndDisplayingSectionFooter: ((UIView, Int) -> Void)? = nil
-
- public var targetIndexPathForMove: ((RowType, (IndexPath, IndexPath)) -> IndexPath)? = nil
- public var indentationLevel: ((RowType, IndexPath) -> Int)? = nil
- public var shouldShowMenu: ((RowType, IndexPath) -> Bool)? = nil
- public var canPerformAction: ((RowType, Selector, Any?, IndexPath) -> Bool)? = nil
- public var performAction: ((RowType, Selector, Any?, IndexPath) -> Void)? = nil
- public var canFocus: ((RowType, IndexPath) -> Bool)? = nil
-
+ public var estimatedHeight: ((IndexPath) -> CGFloat)?
+
+ public var shouldHighlight: ((RowType, IndexPath) -> Bool)?
+ public var didHighlight: ((RowType, IndexPath) -> Void)?
+ public var didUnhighlight: ((RowType, IndexPath) -> Void)?
+
+ public var willSelect: ((RowType, IndexPath) -> IndexPath?)?
+ public var willDeselect: ((RowType, IndexPath) -> IndexPath?)?
+ public var didSelect: ((RowType, IndexPath) -> SelectionResult)?
+ public var didDeselect: ((RowType, IndexPath) -> Void)?
+
+ public var willDisplay: ((RowType, UITableViewCell, IndexPath) -> Void)?
+ public var didEndDisplaying: ((UITableViewCell, IndexPath) -> Void)?
+
+ public var editingStyle: ((RowType, IndexPath) -> UITableViewCell.EditingStyle)?
+ public var titleForDeleteConfirmationButton: ((RowType, IndexPath) -> String?)?
+ public var editActions: ((RowType, IndexPath) -> [UITableViewRowAction]?)?
+ public var shouldIndentWhileEditing: ((RowType, IndexPath) -> Bool)?
+ public var willBeginEditing: ((RowType, IndexPath) -> Void)?
+ public var didEndEditing: ((IndexPath?) -> Void)?
+
+ public var sectionHeader: ((SectionType, Int) -> HeaderFooter)?
+ public var sectionFooter: ((SectionType, Int) -> HeaderFooter)?
+
+ public var sectionHeaderHeight: ((SectionType, Int) -> SectionHeight)?
+ public var sectionFooterHeight: ((SectionType, Int) -> SectionHeight)?
+
+ public var willDisplaySectionHeader: ((SectionType, UIView, Int) -> Void)?
+ public var willDisplaySectionFooter: ((SectionType, UIView, Int) -> Void)?
+
+ public var didEndDisplayingSectionHeader: ((UIView, Int) -> Void)?
+ public var didEndDisplayingSectionFooter: ((UIView, Int) -> Void)?
+
+ public var targetIndexPathForMove: ((RowType, (IndexPath, IndexPath)) -> IndexPath)?
+ public var indentationLevel: ((RowType, IndexPath) -> Int)?
+ public var shouldShowMenu: ((RowType, IndexPath) -> Bool)?
+ public var canPerformAction: ((RowType, Selector, Any?, IndexPath) -> Bool)?
+ public var performAction: ((RowType, Selector, Any?, IndexPath) -> Void)?
+ public var canFocus: ((RowType, IndexPath) -> Bool)?
+
// MARK: Swipe Actions (iOS 11+ only)
- private var _leadingSwipeActions: ((RowType, IndexPath) -> Any?)? = nil
- private var _trailingSwipeActions: ((RowType, IndexPath) -> Any?)? = nil
-
+
+ private var _leadingSwipeActions: ((RowType, IndexPath) -> Any?)?
+ private var _trailingSwipeActions: ((RowType, IndexPath) -> Any?)?
+
+ public var _configurationForMenuAtLocationClosure: ((RowType, IndexPath) -> Any)?
+
// MARK: UITableViewDataSourcePrefetching
-
- public var prefetchRows: (([IndexPath]) -> Void)? = nil
- public var cancelPrefetching: (([IndexPath]) -> Void)? = nil
-
- public weak var fallbackDataSourcePrefetching: UITableViewDataSourcePrefetching? = nil
-
+
+ public var prefetchRows: (([IndexPath]) -> Void)?
+ public var cancelPrefetching: (([IndexPath]) -> Void)?
+
+ public weak var fallbackDataSourcePrefetching: UITableViewDataSourcePrefetching?
+
// MARK: Fallback delegate
-
+
/// Fallback used when DataSource doesn't handle delegate method itself.
/// - Note: The fallback delegate needs to be set *before* setting the table view's delegate, otherwise certain delegate methods will never be called.
- public weak var fallbackDelegate: UITableViewDelegate? = nil
-
- public override func forwardingTarget(for aSelector: Selector!) -> Any? {
+ public weak var fallbackDelegate: UITableViewDelegate?
+
+ override public func forwardingTarget(for _: Selector!) -> Any? {
return fallbackDelegate
}
-
- public override func responds(to aSelector: Selector!) -> Bool {
+
+ override public func responds(to aSelector: Selector!) -> Bool {
if super.responds(to: aSelector) {
if #available(iOS 11.0, *) {
switch aSelector {
@@ -108,126 +102,152 @@ public class DataSource: NSObject {
return true
}
}
-
+
return fallbackDelegateResponds(to: aSelector)
}
-
+
private func fallbackDelegateResponds(to aSelector: Selector!) -> Bool {
let result = fallbackDelegate?.responds(to: aSelector) ?? false
return result
}
-
+
@available(iOS 11.0, *)
private var isLeadingSwipeActionsImplemented: Bool {
if _leadingSwipeActions != nil {
return true
}
-
+
return cellDescriptors.values.contains(where: { ($0 as? CellDescriptorTypeiOS11)?.leadingSwipeActionsClosure != nil })
}
-
+
@available(iOS 11.0, *)
private var isTrailingSwipeActionsImplemented: Bool {
if _trailingSwipeActions != nil {
return true
}
-
+
return cellDescriptors.values.contains(where: { ($0 as? CellDescriptorTypeiOS11)?.trailingSwipeActionsClosure != nil })
}
-
+
+ // MARK: ContextMenu
+
// MARK: Additional
-
- public var isRowHidden: ((RowType, IndexPath) -> Bool)? = nil
- public var isSectionHidden: ((SectionType, Int) -> Bool)? = nil
- public var update: ((RowType, UITableViewCell, IndexPath) -> Void)? = nil
-
+
+ public var isRowHidden: ((RowType, IndexPath) -> Bool)?
+ public var isSectionHidden: ((SectionType, Int) -> Bool)?
+ public var update: ((RowType, UITableViewCell, IndexPath) -> Void)?
+
// MARK: Internal
-
+
var cellDescriptors: [String: CellDescriptorType] = [:]
var sectionDescriptors: [String: SectionDescriptorType] = [:]
-
+
var reuseIdentifiers: Set = []
let registerNibs: Bool
-
+
// MARK: Init
-
+
public init(cellDescriptors: [CellDescriptorType], sectionDescriptors: [SectionDescriptorType] = [], registerNibs: Bool = true) {
self.registerNibs = registerNibs
super.init()
-
+
for d in cellDescriptors {
self.cellDescriptors[d.rowIdentifier] = d
}
-
- self.addDescriptorIfNotSet(SeparatorLineCell.descriptorLine)
- self.addDescriptorIfNotSet(SeparatorLineCell.descriptorCustomView)
-
+
+ addDescriptorIfNotSet(SeparatorLineCell.descriptorLine)
+ addDescriptorIfNotSet(SeparatorLineCell.descriptorCustomView)
+
let defaultSectionDescriptors: [SectionDescriptorType] = [
SectionDescriptor(),
SectionDescriptor()
- .header { (title, _) in
+ .header { title, _ in
.title(title)
- }
+ },
]
-
+
for d in defaultSectionDescriptors {
self.sectionDescriptors[d.identifier] = d
}
-
+
for d in sectionDescriptors {
self.sectionDescriptors[d.identifier] = d
}
}
-
+
private func addDescriptorIfNotSet(_ descriptor: CellDescriptorType) {
- if self.cellDescriptors[descriptor.rowIdentifier] == nil {
- self.cellDescriptors[descriptor.rowIdentifier] = descriptor
+ if cellDescriptors[descriptor.rowIdentifier] == nil {
+ cellDescriptors[descriptor.rowIdentifier] = descriptor
}
}
-
+
// MARK: Getters & Setters
-
- public func section(at index: Int) -> SectionType {
+
+ public func section(at index: Int) -> SectionType? {
+ guard sections.count > index else {
+ return nil
+ }
+
return sections[index]
}
-
- public func row(at indexPath: IndexPath) -> RowType {
- return sections[indexPath.section].row(at: indexPath.row)
+
+ public func row(at indexPath: IndexPath) -> RowType? {
+ guard sections.count > indexPath.section else {
+ return nil
+ }
+
+ let section = sections[indexPath.section]
+
+ guard section.numberOfRows > indexPath.row else {
+ return nil
+ }
+
+ return section.row(at: indexPath.row)
}
-
- public func visibleSection(at index: Int) -> SectionType {
+
+ public func visibleSection(at index: Int) -> SectionType? {
+ guard visibleSections.count > index else {
+ return nil
+ }
+
return visibleSections[index]
}
-
- public func visibleRow(at indexPath: IndexPath) -> RowType {
- return visibleSections[indexPath.section].visibleRow(at: indexPath.row)
- }
-
- // MARK: Cell Descriptors
-
- public func cellDescriptor(at indexPath: IndexPath) -> CellDescriptorType {
- let row = visibleRow(at: indexPath)
+
+ public func visibleRow(at indexPath: IndexPath) -> RowType? {
+ guard visibleSections.count > indexPath.section else {
+ return nil
+ }
- if let cellDescriptor = cellDescriptors[row.identifier] {
- return cellDescriptor
- } else {
- fatalError("[DataSource] no cellDescriptor found for indexPath \(indexPath) with identifier \(row.identifier)")
+ let visibleSection = visibleSections[indexPath.section]
+
+ guard visibleSection.numberOfVisibleRows > indexPath.row else {
+ return nil
}
+
+ return visibleSection.visibleRow(at: indexPath.row)
}
-
- public func cellDescriptor(for rowIdentifier: String) -> CellDescriptorType {
- if let cellDescriptor = cellDescriptors[rowIdentifier] {
- return cellDescriptor
- } else {
- fatalError("[DataSource] no cellDescriptor found for rowIdentifier \(rowIdentifier)")
+
+ // MARK: Cell Descriptors
+
+ public func cellDescriptor(at indexPath: IndexPath) -> CellDescriptorType? {
+ guard let row = visibleRow(at: indexPath) else {
+ return nil
}
+
+ return cellDescriptors[row.identifier]
+ }
+
+ public func cellDescriptor(for rowIdentifier: String) -> CellDescriptorType? {
+ cellDescriptors[rowIdentifier]
}
-
+
// MARK: Section Descriptors
-
+
public func sectionDescriptor(at index: Int) -> SectionDescriptorType? {
- let section = visibleSection(at: index)
-
+ guard let section = visibleSection(at: index) else {
+ return nil
+ }
+
if let sectionDescriptor = sectionDescriptors[section.identifier] {
return sectionDescriptor
} else {
@@ -235,7 +255,7 @@ public class DataSource: NSObject {
return nil
}
}
-
+
public func sectionDescriptor(for identifier: String) -> SectionDescriptorType? {
if let sectionDescriptor = sectionDescriptors[identifier] {
return sectionDescriptor
@@ -246,45 +266,45 @@ public class DataSource: NSObject {
}
// MARK: Visibility
-
+
internal func updateVisibility() {
visibleSections = updateSectionVisiblity()
}
-
+
internal func updateSectionVisiblity() -> [SectionType] {
var visibleSections = [SectionType]()
-
+
for (index, section) in sections.enumerated() {
section.updateVisibility(sectionIndex: index, dataSource: self)
-
+
let sectionDescriptor = self.sectionDescriptor(for: section.identifier)
let isHidden: Bool
-
+
if let closure = sectionDescriptor?.isHiddenClosure ?? isSectionHidden {
isHidden = closure(section, index)
} else {
isHidden = false
}
-
- if isHidden == false && section.numberOfVisibleRows > 0 {
+
+ if isHidden == false, section.numberOfVisibleRows > 0 {
visibleSections.append(section)
}
}
-
+
return visibleSections
}
-
+
// MARK: Reload Data
-
+
public func reloadData(_ tableView: UITableView, animated: Bool) {
if tableView.dataSource == nil {
tableView.dataSource = self
}
-
+
if tableView.delegate == nil {
tableView.delegate = self
}
-
+
if animated {
reloadDataAnimated(tableView)
} else {
@@ -292,7 +312,7 @@ public class DataSource: NSObject {
tableView.reloadData()
}
}
-
+
public func reloadDataAnimated(
_ tableView: UITableView,
rowDeletionAnimation: UITableView.RowAnimation = .fade,
@@ -300,41 +320,40 @@ public class DataSource: NSObject {
rowReloadAnimation: UITableView.RowAnimation = .none,
sectionDeletionAnimation: UITableView.RowAnimation = .fade,
sectionInsertionAnimation: UITableView.RowAnimation = .fade
- ) {
-
+ ) {
let oldSections = visibleSections.map { $0.diffableSection }
let newSections = updateSectionVisiblity()
let diffableNewSections = newSections.map { $0.diffableSection }
-
+
let diff = computeDiff(oldSections: oldSections, newSections: diffableNewSections)
let updates = computeUpdate(oldSections: oldSections, newSections: diffableNewSections)
-
- self.visibleSections = newSections
-
+
+ visibleSections = newSections
+
if rowReloadAnimation == .none {
for update in updates {
updateRow(tableView, row: update.to.row, at: update.from.indexPath)
}
}
-
+
tableView.apply(
batch: Batch(diff: diff, updates: updates),
rowDeletionAnimation: rowDeletionAnimation,
rowInsertionAnimation: rowInsertionAnimation,
rowReloadAnimation: rowReloadAnimation,
sectionDeletionAnimation: sectionDeletionAnimation,
- sectionInsertionAnimation: sectionInsertionAnimation)
+ sectionInsertionAnimation: sectionInsertionAnimation
+ )
}
-
+
public func updateRow(_ tableView: UITableView, row: RowType, at indexPath: IndexPath) {
let cellDescriptor = self.cellDescriptor(for: row.identifier)
-
- let closure =
- cellDescriptor.updateClosure
- ?? update
- ?? cellDescriptor.configureClosure
- ?? configure
-
+
+ let updateClosure = cellDescriptor?.updateClosure ?? update
+ let configureClosure = cellDescriptor?.configureClosure ?? configure
+
+ let closure = updateClosure ?? configureClosure
+
if let cell = tableView.cellForRow(at: indexPath), let closure = closure {
closure(row, cell, indexPath)
}
@@ -342,36 +361,53 @@ public class DataSource: NSObject {
}
@available(iOS 11,*)
-extension DataSource {
- public var leadingSwipeActions: ((RowType, IndexPath) -> UISwipeActionsConfiguration?)? {
+public extension DataSource {
+ var leadingSwipeActions: ((RowType, IndexPath) -> UISwipeActionsConfiguration?)? {
get {
if _leadingSwipeActions == nil {
return nil
}
-
- return { [weak self] (rowType, indexPath) in
- return self?._leadingSwipeActions?(rowType, indexPath) as? UISwipeActionsConfiguration
+
+ return { [weak self] rowType, indexPath in
+ self?._leadingSwipeActions?(rowType, indexPath) as? UISwipeActionsConfiguration
}
}
set {
_leadingSwipeActions = newValue
}
}
-
- public var trailingSwipeActions: ((RowType, IndexPath) -> UISwipeActionsConfiguration?)? {
+
+ var trailingSwipeActions: ((RowType, IndexPath) -> UISwipeActionsConfiguration?)? {
get {
if _trailingSwipeActions == nil {
return nil
}
-
- return { [weak self] (rowType, indexPath) in
- return self?._trailingSwipeActions?(rowType, indexPath) as? UISwipeActionsConfiguration
+
+ return { [weak self] rowType, indexPath in
+ self?._trailingSwipeActions?(rowType, indexPath) as? UISwipeActionsConfiguration
}
}
set {
_trailingSwipeActions = newValue
}
}
-
}
+@available(iOS 13,*)
+public extension DataSource {
+ var configurationForMenuAtLocationClosure: ((RowType, IndexPath) -> UIContextMenuConfiguration?)? {
+ get {
+ if _configurationForMenuAtLocationClosure == nil {
+ return nil
+ }
+
+ return { [weak self] rowType, indexPath in
+ self?._configurationForMenuAtLocationClosure?(rowType, indexPath) as? UIContextMenuConfiguration
+ }
+ }
+
+ set {
+ _configurationForMenuAtLocationClosure = newValue
+ }
+ }
+}
diff --git a/DataSource/Info.plist b/DataSource/Info.plist
index 9e6da47..ca23c84 100644
--- a/DataSource/Info.plist
+++ b/DataSource/Info.plist
@@ -15,11 +15,11 @@
CFBundlePackageType
FMWK
CFBundleShortVersionString
- 5.2.0
+ $(MARKETING_VERSION)
CFBundleSignature
????
CFBundleVersion
- 50
+ $(CURRENT_PROJECT_VERSION)
NSPrincipalClass
diff --git a/DataSource/Row.swift b/DataSource/Row.swift
index 410bb27..b8a6bb0 100644
--- a/DataSource/Row.swift
+++ b/DataSource/Row.swift
@@ -1,17 +1,9 @@
-//
-// Row.swift
-// DataSource
-//
-// Created by Matthias Buchetics on 21/02/2017.
-// Copyright © 2017 aaa - all about apps GmbH. All rights reserved.
-//
-
import Foundation
// MARK: - RowType
public protocol RowType {
-
+
var identifier: String { get }
var item: Any { get }
var diffableItem: Diffable? { get }
@@ -20,19 +12,19 @@ public protocol RowType {
// MARK: - Row
public struct Row: RowType {
-
+
public let identifier: String
public let item: Any
-
+
public var diffableItem: Diffable? {
return item as? Diffable
}
-
+
public init(_ item: Any, identifier: String? = nil) {
self.identifier = identifier ?? String(describing: type(of: item))
self.item = item
}
-
+
public func with(identifier: String) -> Row {
return Row(item, identifier: identifier)
}
@@ -41,34 +33,34 @@ public struct Row: RowType {
// MARK: - LazyRowType
public protocol LazyRowType: RowType {
-
+
var anyItemClosure: () -> Any { get }
}
// MARK: - LazyRow
public struct LazyRow
- : LazyRowType {
-
+
public let identifier: String
public let itemClosure: () -> Item
public var item: Any {
return itemClosure()
}
-
+
public var anyItemClosure: () -> Any {
return itemClosure
}
-
+
public var diffableItem: Diffable? {
return nil
}
-
+
public init(_ item: @escaping () -> Item, identifier: String? = nil) {
self.identifier = identifier ?? String(describing: Item.self)
- self.itemClosure = item
+ itemClosure = item
}
-
+
public func with(identifier: String) -> LazyRow
- {
return LazyRow(itemClosure, identifier: identifier)
}
@@ -76,9 +68,9 @@ public struct LazyRow
- : LazyRowType {
// MARK: - Extensions
-extension Array {
-
- public func rows(_ identifier: String? = nil) -> [Row] {
- return self.map { Row($0, identifier: identifier) }
+public extension Array {
+
+ func rows(_ identifier: String? = nil) -> [Row] {
+ return map { Row($0, identifier: identifier) }
}
}
diff --git a/DataSource/Section.swift b/DataSource/Section.swift
index d95870d..528d604 100644
--- a/DataSource/Section.swift
+++ b/DataSource/Section.swift
@@ -15,6 +15,7 @@ public protocol SectionType {
var identifier: String { get }
var content: Any? { get }
var numberOfVisibleRows: Int { get }
+ var numberOfRows: Int { get }
var diffableSection: DiffableSection { get }
@@ -60,6 +61,10 @@ open class Section: SectionType {
return visibleRows.count
}
+ public var numberOfRows: Int {
+ return rows.count
+ }
+
public func row(at index: Int) -> RowType {
return rows[index]
}
@@ -141,6 +146,10 @@ public class LazySection: LazySectionType {
return rowCount()
}
+ public var numberOfRows: Int {
+ rowCount()
+ }
+
// there is no difference between row and visibleRow for on-demand sections,
// you should only return visible rows
diff --git a/DataSource/SeparatedSection/SeparatorLineCell.swift b/DataSource/SeparatedSection/SeparatorLineCell.swift
index 9188003..3173d8f 100644
--- a/DataSource/SeparatedSection/SeparatorLineCell.swift
+++ b/DataSource/SeparatedSection/SeparatorLineCell.swift
@@ -36,22 +36,51 @@ public struct SeparatorStyle: Equatable {
}
+class SeparatorLineCell: UITableViewCell, AutoRegisterCell {
-
-class SeparatorLineCell: UITableViewCell {
-
- @IBOutlet weak var separator: UIView!
- @IBOutlet weak var leftInsetConstraint: NSLayoutConstraint!
- @IBOutlet weak var rightInsetConstraint: NSLayoutConstraint!
- @IBOutlet weak var topInsetConstraint: NSLayoutConstraint!
- @IBOutlet weak var bottomInsetConstraint: NSLayoutConstraint!
-
- override func awakeFromNib() {
- super.awakeFromNib()
+ var separator: UIView!
+ var leftInsetConstraint: NSLayoutConstraint!
+ var rightInsetConstraint: NSLayoutConstraint!
+ var topInsetConstraint: NSLayoutConstraint!
+ var bottomInsetConstraint: NSLayoutConstraint!
+
+ override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
+ super.init(style: style, reuseIdentifier: reuseIdentifier)
+
+ customInit()
+ }
+
+ required init?(coder: NSCoder) {
+ super.init(coder: coder)
+ customInit()
+ }
+
+ override func accessibilityElementCount() -> Int {
+ return 0
+ }
+
+ func customInit() {
+ isAccessibilityElement = false
selectionStyle = .none
- separator.backgroundColor = .clear
backgroundColor = .clear
+
+ separator = UIView()
+ separator.translatesAutoresizingMaskIntoConstraints = false
+ contentView.addSubview(separator)
+ separator.backgroundColor = .clear
+
+ leftInsetConstraint = separator.leftAnchor.constraint(equalTo: contentView.leftAnchor)
+ topInsetConstraint = separator.topAnchor.constraint(equalTo: contentView.topAnchor)
+ rightInsetConstraint = separator.rightAnchor.constraint(equalTo: contentView.rightAnchor)
+ bottomInsetConstraint = separator.bottomAnchor.constraint(equalTo: contentView.bottomAnchor)
+
+ NSLayoutConstraint.activate([
+ leftInsetConstraint,
+ topInsetConstraint,
+ rightInsetConstraint,
+ bottomInsetConstraint
+ ])
}
func configure(viewModel: SeparatorLineViewModel) {
diff --git a/DataSource/SeparatedSection/SeparatorLineCell.xib b/DataSource/SeparatedSection/SeparatorLineCell.xib
deleted file mode 100644
index 2fcbebd..0000000
--- a/DataSource/SeparatedSection/SeparatorLineCell.xib
+++ /dev/null
@@ -1,43 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/DataSource/SeparatedSection/SeparatorLineViewModel.swift b/DataSource/SeparatedSection/SeparatorLineViewModel.swift
index 8945614..f8652f0 100644
--- a/DataSource/SeparatedSection/SeparatorLineViewModel.swift
+++ b/DataSource/SeparatedSection/SeparatorLineViewModel.swift
@@ -8,9 +8,9 @@
import UIKit
-class SeparatorLineViewModel: Diffable {
+public class SeparatorLineViewModel: Diffable {
- let diffIdentifier: String
+ public let diffIdentifier: String
let style: SeparatorStyle
init(diffIdentifier: String, style: SeparatorStyle) {
@@ -22,7 +22,7 @@ class SeparatorLineViewModel: Diffable {
return Row(self)
}
- func isEqualToDiffable(_ other: Diffable?) -> Bool {
+ public func isEqualToDiffable(_ other: Diffable?) -> Bool {
guard let other = other as? SeparatorLineViewModel else { return false }
return other.style == self.style
}
diff --git a/DataSource/UITableViewExtensions.swift b/DataSource/UITableViewExtensions.swift
index 2301e6c..3858968 100644
--- a/DataSource/UITableViewExtensions.swift
+++ b/DataSource/UITableViewExtensions.swift
@@ -41,8 +41,8 @@ struct Batch {
sectionDeletions.insert(at)
case let .insertSection(at):
sectionInsertions.insert(at)
- case let .moveSection(move):
- sectionMoves.append((move.from, move.to))
+ case let .moveSection(from, to):
+ sectionMoves.append((from, to))
}
}
diff --git a/DataSourceTests/ConcurrentReloadSelectTest.swift b/DataSourceTests/ConcurrentReloadSelectTest.swift
new file mode 100644
index 0000000..39c9d6c
--- /dev/null
+++ b/DataSourceTests/ConcurrentReloadSelectTest.swift
@@ -0,0 +1,165 @@
+@testable import DataSource
+import Foundation
+import XCTest
+
+public extension XCTestCase {
+ var given: Given { Given() }
+ var when: When { When() }
+ var then: Then { Then() }
+}
+
+public struct Given {}
+public struct When {}
+public struct Then {}
+
+class ConcurrentReloadSelectTest: XCTestCase {
+ class State {
+ let tableView = UITableView()
+
+ lazy var dataSource: DataSource = {
+ DataSource(cellDescriptors: [
+ MockCell.descriptor
+ .didSelect { [weak self] viewModel, _ in
+ self?.selectedViewModel = viewModel
+ return .deselect
+ },
+ ])
+ }()
+
+ var selectedViewModel: MockCellViewModel?
+ }
+
+ var state: State!
+
+ override func setUp() {
+ super.setUp()
+ state = State()
+ }
+
+ override func tearDown() {
+ state = nil
+ super.tearDown()
+ }
+
+ func testSectionRemoved() async {
+ await given
+ .setupTableView(state: state)
+
+ await when
+ .populateData(state: state, numberOfRows: 100)
+ .emptyTableView(state: state)
+ .selectCellAt(150, state: state)
+
+ await then
+ .nothingSelected(state: state)
+ }
+
+ func testSelection() async {
+ await given
+ .setupTableView(state: state)
+
+ await when
+ .populateData(state: state, numberOfRows: 100)
+ .selectCellAt(50, state: state)
+
+ then
+ .selectedId(state: state, id: 50)
+ }
+
+ func testElementRemoved() async {
+ await given
+ .setupTableView(state: state)
+
+ await when
+ .populateData(state: state, numberOfRows: 100)
+ .selectCellAt(50, state: state)
+ .removeItemsFromSection(state: state)
+
+ then
+ .selectedId(state: state, id: 50)
+ }
+}
+
+extension Given {
+
+ @discardableResult
+ @MainActor
+ func setupTableView(state: ConcurrentReloadSelectTest.State) -> Given {
+ state.tableView.delegate = state.dataSource
+ state.tableView.dataSource = state.dataSource
+ return self
+ }
+}
+
+extension When {
+
+ @discardableResult
+ @MainActor
+ func populateData(state: ConcurrentReloadSelectTest.State, numberOfRows: Int) -> Self {
+ let items = Array(0.. Self {
+ state.dataSource.tableView(state.tableView, didSelectRowAt: .init(row: index, section: 0))
+ return self
+ }
+
+ @discardableResult
+ @MainActor
+ func emptyTableView(state: ConcurrentReloadSelectTest.State) async -> Self {
+ state.dataSource.sections = []
+ state.dataSource.reloadData(state.tableView, animated: false)
+ return self
+ }
+
+ @discardableResult
+ @MainActor
+ func removeItemsFromSection(state: ConcurrentReloadSelectTest.State) async -> Self {
+ state.dataSource.sections = [Section(items: [Section(items: [MockCellViewModel(id: 0)])])]
+ state.dataSource.reloadData(state.tableView, animated: false)
+ return self
+ }
+}
+
+extension Then {
+ @discardableResult
+ func nothingSelected(state: ConcurrentReloadSelectTest.State) async -> Self {
+ XCTAssertNil(state.selectedViewModel, "nothing should be selected but element with id \(state.selectedViewModel!.id) was selected")
+ return self
+ }
+
+ @discardableResult
+ func selectedId(state: ConcurrentReloadSelectTest.State, id: Int) -> Self {
+ do {
+ let selectedId = try XCTUnwrap(state.selectedViewModel?.id, "there should have been a selection")
+ XCTAssertEqual(selectedId, id, "mismatch on id selection: selected \(selectedId) but should have been \(id)")
+ } catch {
+ XCTFail("unwrap of selected cell failed")
+ }
+ return self
+ }
+}
+
+class MockCell: UITableViewCell, AutoRegisterCell {
+ public func configure(viewModel _: MockCellViewModel) {}
+
+ static var descriptor: CellDescriptor {
+ return CellDescriptor().configure { viewModel, cell, _ in
+ cell.configure(viewModel: viewModel)
+ }
+ }
+}
+
+class MockCellViewModel {
+ let id: Int
+
+ init(id: Int) {
+ self.id = id
+ }
+}
diff --git a/DataSourceTests/DataSourceTests.swift b/DataSourceTests/DataSourceTests.swift
deleted file mode 100644
index e4d8cf0..0000000
--- a/DataSourceTests/DataSourceTests.swift
+++ /dev/null
@@ -1,37 +0,0 @@
-//
-// DataSourceTests.swift
-// DataSourceTests
-//
-// Created by Matthias Buchetics on 22/02/2017.
-// Copyright © 2017 aaa - all about apps GmbH. All rights reserved.
-//
-
-import XCTest
-
-@testable import DataSource
-
-class DataSourceTests: XCTestCase {
-
- override func setUp() {
- super.setUp()
- // Put setup code here. This method is called before the invocation of each test method in the class.
- }
-
- override func tearDown() {
- // Put teardown code here. This method is called after the invocation of each test method in the class.
- super.tearDown()
- }
-
- func testExample() {
- // This is an example of a functional test case.
- // Use XCTAssert and related functions to verify your tests produce the correct results.
- }
-
- func testPerformanceExample() {
- // This is an example of a performance test case.
- self.measure {
- // Put the code you want to measure the time of here.
- }
- }
-
-}
diff --git a/Example/Info.plist b/Example/Info.plist
index b72b83f..64e2267 100644
--- a/Example/Info.plist
+++ b/Example/Info.plist
@@ -15,11 +15,11 @@
CFBundlePackageType
APPL
CFBundleShortVersionString
- 5.2.0
+ $(MARKETING_VERSION)
CFBundleSignature
????
CFBundleVersion
- 50
+ $(CURRENT_PROJECT_VERSION)
LSRequiresIPhoneOS
UILaunchStoryboardName
diff --git a/Example/Storyboards/Base.lproj/Main.storyboard b/Example/Storyboards/Base.lproj/Main.storyboard
index 2a2cd06..4944c47 100644
--- a/Example/Storyboards/Base.lproj/Main.storyboard
+++ b/Example/Storyboards/Base.lproj/Main.storyboard
@@ -1,11 +1,9 @@
-
-
-
-
+
+
-
+
@@ -15,7 +13,7 @@
-
+
@@ -49,6 +47,8 @@
+
+
@@ -112,7 +112,7 @@
-
+
@@ -212,12 +212,11 @@
-
+
-
-
+
@@ -239,17 +238,17 @@
-
+
-
+
@@ -345,5 +344,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Example/ViewControllers/Cells/TextCell.swift b/Example/ViewControllers/Cells/TextCell.swift
new file mode 100644
index 0000000..1cf480b
--- /dev/null
+++ b/Example/ViewControllers/Cells/TextCell.swift
@@ -0,0 +1,15 @@
+//
+// TextCell.swift
+// Example
+//
+// Created by Matthias Buchetics on 23.03.20.
+// Copyright © 2020 aaa - all about apps GmbH. All rights reserved.
+//
+
+import UIKit
+
+class TextCell: UITableViewCell {
+
+ @IBOutlet weak var descriptionLabel: UILabel!
+
+}
diff --git a/Example/ViewControllers/Cells/TextCell.xib b/Example/ViewControllers/Cells/TextCell.xib
new file mode 100644
index 0000000..dc8d5e5
--- /dev/null
+++ b/Example/ViewControllers/Cells/TextCell.xib
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Example/ViewControllers/ContextMenuViewController.swift b/Example/ViewControllers/ContextMenuViewController.swift
new file mode 100644
index 0000000..c4b23bc
--- /dev/null
+++ b/Example/ViewControllers/ContextMenuViewController.swift
@@ -0,0 +1,67 @@
+//
+// ContextMenuViewController.swift
+// Example
+//
+// Created by Sandin Dulić on 09.09.20.
+// Copyright © 2020 aaa - all about apps GmbH. All rights reserved.
+//
+
+import UIKit
+import DataSource
+
+@available(iOS 13.0, *)
+class ContextMenuViewController: UITableViewController {
+ lazy var dataSource: DataSource = {
+ DataSource(
+ cellDescriptors: [
+ CellDescriptor()
+ .configure { item, cell, _ in
+ cell.textLabel?.text = item
+ }
+ .configurationForMenuAtLocation { [weak self] _, indexPath -> UIContextMenuConfiguration in
+ guard let self = self else { return UIContextMenuConfiguration() }
+ let index = indexPath.row
+
+ let identifier = "\(index)" as NSString
+ return self.createContextMenuConfiguration(with: identifier)
+ }
+ ])
+ }()
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+
+ title = "Context menu example"
+
+ tableView.dataSource = dataSource
+ tableView.delegate = dataSource
+
+ dataSource.sections = createSections()
+ dataSource.reloadData(tableView, animated: false)
+ }
+
+ func createSections() -> [Section] {
+ let items = ["One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten"]
+
+
+ return [
+ Section(items: items)
+ ]
+ }
+
+ private func createContextMenuConfiguration(with identifier: NSString) -> UIContextMenuConfiguration {
+ UIContextMenuConfiguration(identifier: identifier, previewProvider: nil) { _ in
+ let mapAction = UIAction(
+ title: "Some title",
+ image: UIImage(systemName: "map")) { _ in
+ }
+
+ let shareAction = UIAction(
+ title: "Some title 2",
+ image: UIImage(systemName: "square.and.arrow.up")) { _ in
+ }
+
+ return UIMenu(title: "", image: nil, children: [mapAction, shareAction])
+ }
+ }
+}
diff --git a/Example/ViewControllers/Examples/DiffViewController.swift b/Example/ViewControllers/Examples/DiffViewController.swift
index 914aced..819a05b 100644
--- a/Example/ViewControllers/Examples/DiffViewController.swift
+++ b/Example/ViewControllers/Examples/DiffViewController.swift
@@ -6,23 +6,22 @@
// Copyright © 2017 aaa - all about apps GmbH. All rights reserved.
//
-import UIKit
import DataSource
+import UIKit
// MARK: - View Controller
class DiffViewController: UITableViewController {
-
var counter = 0
lazy var dataSource: DataSource = {
DataSource(
cellDescriptors: [
CellDescriptor()
- .configure { (item, cell, indexPath) in
+ .configure { item, cell, _ in
cell.textLabel?.text = item.text
}
- .update { (item, cell, indexPath) in
+ .update { item, cell, _ in
cell.textLabel?.update(text: item.text, animated: true)
}
])
@@ -56,22 +55,21 @@ class DiffViewController: UITableViewController {
})
]
}
-
+
@IBAction func refresh(_ sender: Any) {
counter += 1
dataSource.sections = createSections()
dataSource.reloadDataAnimated(tableView,
- rowDeletionAnimation: .automatic,
- rowInsertionAnimation: .automatic,
- rowReloadAnimation: .none)
+ rowDeletionAnimation: .automatic,
+ rowInsertionAnimation: .automatic,
+ rowReloadAnimation: .none)
}
}
// MARK: - Diff Item
struct DiffItem: Hashable {
-
let value: Int
let text: String
@@ -85,4 +83,4 @@ struct DiffItem: Hashable {
}
}
-extension DiffItem: Diffable { }
+extension DiffItem: Diffable {}
diff --git a/Example/ViewControllers/ExpandableCellViewController.swift b/Example/ViewControllers/ExpandableCellViewController.swift
new file mode 100644
index 0000000..622de53
--- /dev/null
+++ b/Example/ViewControllers/ExpandableCellViewController.swift
@@ -0,0 +1,76 @@
+//
+// ExpandableCellViewController.swift
+// Example
+//
+// Created by Matthias Buchetics on 23.03.20.
+// Copyright © 2020 aaa - all about apps GmbH. All rights reserved.
+//
+
+import UIKit
+import DataSource
+
+class ExpandableItem: Diffable {
+
+ let id = UUID().uuidString
+ let text: String
+ var isExpanded: Bool = false
+
+ init(text: String) {
+ self.text = text
+ }
+
+ var diffIdentifier: String {
+ return id
+ }
+
+ func isEqualToDiffable(_ other: Diffable?) -> Bool {
+ return false
+ }
+}
+
+// MARK: - View Controller
+
+class ExpandableCellViewController: UITableViewController {
+
+ lazy var dataSource: DataSource = {
+ DataSource(
+ cellDescriptors: [
+ CellDescriptor()
+ .configure { (item, cell, indexPath) in
+ cell.descriptionLabel?.text = item.text
+ cell.descriptionLabel.numberOfLines = item.isExpanded ? 0 : 3
+ }
+ .didSelect { [weak self] (item, _) -> SelectionResult in
+ self?.toggleItem(item)
+ return .deselect
+ }
+ .height { (item, _) -> CGFloat in
+ return UITableView.automaticDimension
+ //return item.isExpanded ? UITableView.automaticDimension : 80.0
+ }
+ ])
+ }()
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+
+ tableView.dataSource = dataSource
+ tableView.delegate = dataSource
+
+ dataSource.sections = createSections()
+ dataSource.reloadData(tableView, animated: false)
+ }
+
+ func toggleItem(_ item: ExpandableItem) {
+ item.isExpanded.toggle()
+ dataSource.reloadData(tableView, animated: true)
+ }
+
+ func createSections() -> [Section] {
+ return [Section(items: items)]
+ }
+
+ var items = [
+ ExpandableItem(text: "Morbi accumsan fermentum posuere vulputate iaculis ac nulla rutrum cum tempus massa vel, erat elit ipsum justo ligula enim luctus conubia est torquent. Inceptos fusce convallis ultricies platea nibh sapien montes per id, eleifend mattis quam dictum dignissim potenti fringilla semper, cubilia nostra eros faucibus neque tortor tempor posuere. Class neque lacinia vitae integer et mi libero ullamcorper fames tortor nullam nulla cursus, placerat orci tristique ipsum sagittis vulputate morbi euismod molestie volutpat cum. Amet condimentum vitae fames vivamus sapien sociis in ligula eget non lectus, pretium libero dis imperdiet hendrerit diam aenean urna sed."),
+ ExpandableItem(text: "Ipsum ligula in ac sociis fringilla penatibus scelerisque mi himenaeos habitant commodo, phasellus fusce rutrum consectetur non duis sagittis elit platea. Ante molestie ac est tempus magna volutpat vulputate nisl tellus, posuere lorem potenti taciti facilisi venenatis lacinia sodales. Venenatis lacinia in purus commodo penatibus mollis, id feugiat ornare torquent nascetur lacus, nulla inceptos varius cras accumsan.")]
+}
diff --git a/Example/ViewControllers/SeparatedSectionViewController.swift b/Example/ViewControllers/SeparatedSectionViewController.swift
index b74bac3..29c1e6a 100644
--- a/Example/ViewControllers/SeparatedSectionViewController.swift
+++ b/Example/ViewControllers/SeparatedSectionViewController.swift
@@ -21,7 +21,18 @@ class SeparatedSectionViewController: UIViewController {
CellDescriptor()
.configure { (item, cell, indexPath) in
cell.textLabel?.text = item.text
- },
+ }
+ .canEdit { [weak self] (_, _) -> Bool in
+ return true
+ }
+ .trailingSwipeAction { [weak self] (_, _) -> UISwipeActionsConfiguration? in
+ return UISwipeActionsConfiguration(actions: [
+ UIContextualAction(style: .destructive, title: "TestAction", handler: { [weak self] (_, _, callback) in
+
+ callback(true)
+ })
+ ])
+ },
CellDescriptor()
.configure { (item, cell, indexPath) in
cell.textLabel?.text = item.text
diff --git a/Example/ViewControllers/StartViewController.swift b/Example/ViewControllers/StartViewController.swift
index 58053eb..ea37b48 100644
--- a/Example/ViewControllers/StartViewController.swift
+++ b/Example/ViewControllers/StartViewController.swift
@@ -30,7 +30,7 @@ class StartViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
-
+ tableView.separatorStyle = .none
tableView.dataSource = dataSource
tableView.delegate = dataSource
var items = [
@@ -40,6 +40,13 @@ class StartViewController: UITableViewController {
Example(title: "Diff & Update", segue: "showDiff"),
Example(title: "Swipe To Delete", segue: "showSwipeToDelete"),
Example(title: "Custom separators", segue: "showSeparatedSection"),
+ Example(title: "Expandable Cell", segue: "showExpandableCell"),
+ Example(title: "Context Menu", segue: "showContextMenuExample")
+ ]
+
+ let separatorItems = [
+ Example(title: "Random Persons", segue: "showRandomPersons"),
+ Example(title: "Form", segue: "showForm"),
]
if #available(iOS 11, *) {
@@ -47,7 +54,13 @@ class StartViewController: UITableViewController {
}
dataSource.sections = [
- Section(items: items)
+ Section(items: items),
+ SeparatedSection(items: separatorItems, styleConfigureClosure: { transition -> SeparatorStyle? in
+ let leftInset: CGFloat = transition.isLast ? 0 : 20
+ return SeparatorStyle(edgeEnsets: UIEdgeInsets(top: 0, left: leftInset, bottom: 0, right: -20),
+ color: UIColor.blue,
+ height: 1.0)
+ })
]
dataSource.reloadData(tableView, animated: false)
diff --git a/LICENSE b/LICENSE
index c9a2f2c..8c55433 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2016 - 2018 Matthias Buchetics
+Copyright (c) 2016 - 2023 all about apps GmbH
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/Package.resolved b/Package.resolved
new file mode 100644
index 0000000..37925f1
--- /dev/null
+++ b/Package.resolved
@@ -0,0 +1,16 @@
+{
+ "object": {
+ "pins": [
+ {
+ "package": "Differ",
+ "repositoryURL": "https://github.com/tonyarnold/Differ.git",
+ "state": {
+ "branch": null,
+ "revision": "e2cca36e7258dd8add88ae46b5ea56509b066e21",
+ "version": "1.4.3"
+ }
+ }
+ ]
+ },
+ "version": 1
+}
diff --git a/Package.swift b/Package.swift
new file mode 100644
index 0000000..1836ca3
--- /dev/null
+++ b/Package.swift
@@ -0,0 +1,24 @@
+// swift-tools-version:5.0
+
+import PackageDescription
+
+let package = Package(
+ name: "DataSource",
+ platforms: [
+ .macOS(.v10_12),
+ .iOS(.v11),
+ .tvOS(.v11),
+ .watchOS(.v3)
+ ],
+ products: [
+ .library(name: "DataSource", targets: ["DataSource"])
+ ],
+ dependencies: [
+ .package(url: "https://github.com/tonyarnold/Differ.git", from: "1.4.3")
+ ],
+ targets: [
+ .target(name: "DataSource", dependencies: ["Differ"], path: "DataSource/"),
+ .testTarget(name: "DataSourceTests", dependencies: ["DataSource"], path: "DataSourceTests/")
+ ],
+ swiftLanguageVersions: [.v5]
+)
diff --git a/README.md b/README.md
index 7ec02af..d716bba 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# DataSource
-[](https://developer.apple.com/swift)
+[](https://developer.apple.com/swift)
[](https://github.com/Carthage/Carthage)
[](https://cocoapods.org/pods/MBDataSource)
@@ -226,12 +226,17 @@ Cells can be registered from custom bundles. You can specify in the cell descrip
let descriptor = CellDescriptor(bundle: customBundle)
```
+### Cell Registration
+If you define your cell types in a separate xib(outside your tableView definition in a storyboard) or entirely in code your cell needs to be registered with the tableView you want to use it with.
+You can either register the cell with the tableView manually(see UITableView docs) or let DataSource do that for you by conforming to the `AutoRegisterCell` protocol.
+
## Version Compatibility
Current Swift compatibility breakdown:
| Swift Version | Framework Version |
| ------------- | ----------------- |
+| 5.1 | 8.x |
| 5.0 | 7.x |
| 4.2 | 6.x |
| 4.1 | 5.x |
@@ -241,12 +246,20 @@ Current Swift compatibility breakdown:
## Installation
+### Swift Package Manager (Recommended)
+
+Add the following dependency to your `Package.swift` file:
+
+```
+.package(url: "https://github.com/allaboutapps/DataSource.git", from: "8.0.0")
+```
+
### Carthage
Add the following line to your [Cartfile](https://github.com/Carthage/Carthage/blob/master/Documentation/Artifacts.md#cartfile).
```
-github "allaboutapps/DataSource", ~> 7.0
+github "allaboutapps/DataSource", ~> 8.0
```
Then run `carthage update`.