Skip to content

Commit 5e4964e

Browse files
committed
Decoupled VSCollectionViewController and VSCollectionViewSectionHandler
1 parent babdc5c commit 5e4964e

18 files changed

+262
-70
lines changed

VSCollectionKit/CollectionKitTestApp/PhotoTumbnailCell.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ class PhotoTumbnailCell: UICollectionViewCell {
3636
super.init(coder: coder)
3737
setUpView()
3838
}
39+
40+
override func prepareForReuse() {
41+
super.prepareForReuse()
42+
imageView.image = nil
43+
}
3944

4045
private func setUpView() {
4146
contentView.addSubview(imageView)

VSCollectionKit/CollectionKitTestApp/PhotosSectionHandler.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ import VSCollectionKit
1111
import VSCollectionViewData
1212

1313
class PhotosSectionHandler: SectionHandler {
14+
15+
var sectionHeaderFooterProvider: SectionHeaderFooterProvider? = nil
16+
var sectionDelegateHandler: SectionDelegateHandler? = nil
17+
1418
var type: String {
1519
return AlbumSectionType.photos.rawValue
1620
}

VSCollectionKit/VSCollectionKit.xcodeproj/project.pbxproj

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
531DDD95243C87D50096EC9D /* VSCollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 531DDD8D243C87D50096EC9D /* VSCollectionViewController.swift */; };
2222
531DDD96243C87D50096EC9D /* VSCollectionViewDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 531DDD8E243C87D50096EC9D /* VSCollectionViewDataSource.swift */; };
2323
531DDD97243C87D50096EC9D /* VSCollectionViewLayoutProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 531DDD8F243C87D50096EC9D /* VSCollectionViewLayoutProvider.swift */; };
24+
5354D53D256AA19D00996534 /* MockDelegateHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5354D53C256AA19D00996534 /* MockDelegateHandler.swift */; };
2425
53A1FED22449A47700BB7F0C /* VSCollectionViewSectionHandlerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53A1FED12449A47700BB7F0C /* VSCollectionViewSectionHandlerTests.swift */; };
2526
53A1FED42449B74300BB7F0C /* VSCollectionViewLayoutProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53A1FED32449B74300BB7F0C /* VSCollectionViewLayoutProviderTests.swift */; };
2627
53A9CADA255D83A700373F74 /* VSCollectionViewData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 531DDD89243C87D50096EC9D /* VSCollectionViewData.swift */; };
@@ -89,6 +90,7 @@
8990
531DDD8D243C87D50096EC9D /* VSCollectionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VSCollectionViewController.swift; sourceTree = "<group>"; };
9091
531DDD8E243C87D50096EC9D /* VSCollectionViewDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VSCollectionViewDataSource.swift; sourceTree = "<group>"; };
9192
531DDD8F243C87D50096EC9D /* VSCollectionViewLayoutProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VSCollectionViewLayoutProvider.swift; sourceTree = "<group>"; };
93+
5354D53C256AA19D00996534 /* MockDelegateHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockDelegateHandler.swift; sourceTree = "<group>"; };
9294
53A1FED12449A47700BB7F0C /* VSCollectionViewSectionHandlerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VSCollectionViewSectionHandlerTests.swift; sourceTree = "<group>"; };
9395
53A1FED32449B74300BB7F0C /* VSCollectionViewLayoutProviderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VSCollectionViewLayoutProviderTests.swift; sourceTree = "<group>"; };
9496
53A9CACB255D839F00373F74 /* libVSCollectionViewData.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libVSCollectionViewData.a; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -182,9 +184,7 @@
182184
5316E2852444DFC900D30576 /* VSCollectionViewDataTests.swift */,
183185
53A1FED12449A47700BB7F0C /* VSCollectionViewSectionHandlerTests.swift */,
184186
53A1FED32449B74300BB7F0C /* VSCollectionViewLayoutProviderTests.swift */,
185-
5316E27B2444872300D30576 /* MockSectionModel.swift */,
186-
5316E27D2444874300D30576 /* MockCellModel.swift */,
187-
5316E27F24448D2F00D30576 /* MockSectionHandler.swift */,
187+
5354D53B256AA17800996534 /* Mock */,
188188
531DDD6D243C859D0096EC9D /* Info.plist */,
189189
);
190190
path = VSCollectionKitTests;
@@ -203,6 +203,17 @@
203203
path = VSCollectionViewController;
204204
sourceTree = "<group>";
205205
};
206+
5354D53B256AA17800996534 /* Mock */ = {
207+
isa = PBXGroup;
208+
children = (
209+
5316E27F24448D2F00D30576 /* MockSectionHandler.swift */,
210+
5354D53C256AA19D00996534 /* MockDelegateHandler.swift */,
211+
5316E27B2444872300D30576 /* MockSectionModel.swift */,
212+
5316E27D2444874300D30576 /* MockCellModel.swift */,
213+
);
214+
path = Mock;
215+
sourceTree = "<group>";
216+
};
206217
53A9CACC255D839F00373F74 /* VSCollectionViewData */ = {
207218
isa = PBXGroup;
208219
children = (
@@ -417,6 +428,7 @@
417428
5316E28024448D2F00D30576 /* MockSectionHandler.swift in Sources */,
418429
53A1FED22449A47700BB7F0C /* VSCollectionViewSectionHandlerTests.swift in Sources */,
419430
5316E27E2444874300D30576 /* MockCellModel.swift in Sources */,
431+
5354D53D256AA19D00996534 /* MockDelegateHandler.swift in Sources */,
420432
5316E28224448E7100D30576 /* VSCollectionViewDataSourceTests.swift in Sources */,
421433
531DDD6C243C859D0096EC9D /* VSCollectionKitTests.swift in Sources */,
422434
5316E27C2444872300D30576 /* MockSectionModel.swift in Sources */,
@@ -616,6 +628,7 @@
616628
PRODUCT_BUNDLE_IDENTIFIER = com.vswamy.vscollectionkit.VSCollectionKit;
617629
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
618630
SKIP_INSTALL = YES;
631+
SUPPORTS_MACCATALYST = NO;
619632
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
620633
SWIFT_VERSION = 5.0;
621634
TARGETED_DEVICE_FAMILY = "1,2";
@@ -632,6 +645,7 @@
632645
DYLIB_COMPATIBILITY_VERSION = 1;
633646
DYLIB_CURRENT_VERSION = 1;
634647
DYLIB_INSTALL_NAME_BASE = "@rpath";
648+
ENABLE_TESTABILITY = YES;
635649
INFOPLIST_FILE = VSCollectionKit/Info.plist;
636650
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
637651
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
@@ -643,6 +657,7 @@
643657
PRODUCT_BUNDLE_IDENTIFIER = com.vswamy.vscollectionkit.VSCollectionKit;
644658
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
645659
SKIP_INSTALL = YES;
660+
SUPPORTS_MACCATALYST = NO;
646661
SWIFT_VERSION = 5.0;
647662
TARGETED_DEVICE_FAMILY = "1,2";
648663
};
@@ -705,6 +720,7 @@
705720
buildSettings = {
706721
CODE_SIGN_STYLE = Automatic;
707722
DEVELOPMENT_TEAM = 6XYPCYQXKC;
723+
ENABLE_TESTABILITY = YES;
708724
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
709725
OTHER_LDFLAGS = "-ObjC";
710726
PRODUCT_NAME = "$(TARGET_NAME)";

VSCollectionKit/VSCollectionKit.xcodeproj/xcshareddata/xcschemes/VSCollectionKit.xcscheme

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
</BuildActionEntries>
2424
</BuildAction>
2525
<TestAction
26-
buildConfiguration = "Debug"
26+
buildConfiguration = "Release"
2727
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
2828
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
2929
shouldUseLaunchSchemeArgsEnv = "YES"
@@ -51,6 +51,16 @@
5151
debugDocumentVersioning = "YES"
5252
debugServiceExtension = "internal"
5353
allowLocationSimulation = "YES">
54+
<BuildableProductRunnable
55+
runnableDebuggingMode = "0">
56+
<BuildableReference
57+
BuildableIdentifier = "primary"
58+
BlueprintIdentifier = "53F85A9B244C6A22001451FB"
59+
BuildableName = "CollectionKitTestApp.app"
60+
BlueprintName = "CollectionKitTestApp"
61+
ReferencedContainer = "container:VSCollectionKit.xcodeproj">
62+
</BuildableReference>
63+
</BuildableProductRunnable>
5464
</LaunchAction>
5565
<ProfileAction
5666
buildConfiguration = "Release"

VSCollectionKit/VSCollectionKit/VSCollectionViewController/VSCollectionViewController.swift

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ open class VSCollectionViewController: UIViewController {
1313

1414
public var collectionView: UICollectionView!
1515
public var collectionViewLayout: UICollectionViewLayout!
16-
public var dataProvider: VSCollectionViewDataSource!
17-
public var delegateHandler: VSCollectionViewDelegate!
18-
public var layoutProvider: VSCollectionViewLayoutProvider!
19-
public var sectionHandler: VSCollectionViewSectionHandller = VSCollectionViewSectionHandller()
16+
public var dataProvider: VSCollectionViewDataSourceAPI!
17+
public var delegateHandler: VSCollectionViewDelegateAPI!
18+
public var layoutProvider: VSCollectionViewLayoutProviderAPI!
19+
public var sectionHandler: VSCollectionViewSectionHandlerAPI = VSCollectionViewSectionHandller()
2020

2121
open override func viewDidLoad() {
2222
super.viewDidLoad()
@@ -35,13 +35,17 @@ open class VSCollectionViewController: UIViewController {
3535
}
3636

3737
open func configureDelegate() {
38+
guard let sectionDelegateHandler = sectionHandler as? VSCollectionViewSectionDelegateHandlerAPI else { return }
3839
delegateHandler = VSCollectionViewDelegate(collectionView: collectionView,
39-
sectionHandler: sectionHandler)
40+
sectionHandler: sectionDelegateHandler)
4041
}
4142

4243
open func configureLayoutProvider() {
44+
guard let sectionLayoutHandler = sectionHandler as? VSCollectionViewSectionLayoutHandlerAPI else {
45+
fatalError("Layout Provider not configured, without which the collection will not be able to render the cells")
46+
}
4347
layoutProvider = VSCollectionViewLayoutProvider(collectionView: collectionView,
44-
sectionHandler: sectionHandler)
48+
sectionHandler: sectionLayoutHandler)
4549
}
4650

4751
open func apply(collectionData: VSCollectionViewData, animated: Bool) {

VSCollectionKit/VSCollectionKit/VSCollectionViewController/VSCollectionViewDataSource.swift

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,18 @@
99
import UIKit
1010
import VSCollectionViewData
1111

12-
public class VSCollectionViewDataSource: NSObject, UICollectionViewDataSource {
12+
public protocol VSCollectionViewDataSourceAPI: UICollectionViewDataSource {
13+
func apply(data: VSCollectionViewData,
14+
animated: Bool)
15+
}
16+
17+
public class VSCollectionViewDataSource: NSObject, VSCollectionViewDataSourceAPI {
1318

1419
unowned private var collectionView: UICollectionView
1520
private var data: VSCollectionViewData?
16-
unowned private var sectionHandler: VSCollectionViewSectionHandller
21+
unowned private var sectionHandler: VSCollectionViewSectionHandlerAPI
1722
public init(collectionView: UICollectionView,
18-
sectionHandler: VSCollectionViewSectionHandller) {
23+
sectionHandler: VSCollectionViewSectionHandlerAPI) {
1924
self.collectionView = collectionView
2025
self.sectionHandler = sectionHandler
2126
super.init()

VSCollectionKit/VSCollectionKit/VSCollectionViewController/VSCollectionViewDelegate.swift

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,26 +9,24 @@
99
import UIKit
1010
import VSCollectionViewData
1111

12-
public class VSCollectionViewDelegate: NSObject, UICollectionViewDelegate {
12+
public protocol VSCollectionViewDelegateAPI: UICollectionViewDelegate {
13+
var data: VSCollectionViewData? { get set }
14+
}
15+
16+
public class VSCollectionViewDelegate: NSObject, VSCollectionViewDelegateAPI {
1317

1418
unowned private var collectionView: UICollectionView
1519
public var data: VSCollectionViewData?
16-
unowned private var sectionHandler: VSCollectionViewSectionHandller
20+
unowned private var sectionHandler: VSCollectionViewSectionDelegateHandlerAPI
1721

1822
public init(collectionView: UICollectionView,
19-
sectionHandler: VSCollectionViewSectionHandller) {
23+
sectionHandler: VSCollectionViewSectionDelegateHandlerAPI) {
2024
self.collectionView = collectionView
2125
self.sectionHandler = sectionHandler
2226
super.init()
2327
collectionView.delegate = self
24-
25-
// TODO: Have to remove this
26-
collectionView.register(UICollectionReusableView.self,
27-
forSupplementaryViewOfKind: "section-header-element-kind",
28-
withReuseIdentifier: "EmptyView")
29-
sectionHandler.registerCells(for: collectionView)
3028
}
31-
29+
3230
public func collectionView(_ collectionView: UICollectionView,
3331
willDisplay cell: UICollectionViewCell,
3432
forItemAt indexPath: IndexPath) {

VSCollectionKit/VSCollectionKit/VSCollectionViewController/VSCollectionViewLayoutProvider.swift

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,20 @@
99
import UIKit
1010
import VSCollectionViewData
1111

12-
public class VSCollectionViewLayoutProvider {
12+
public protocol VSCollectionViewLayoutProviderAPI {
13+
var data: VSCollectionViewData? { get set }
14+
func collectionLayout(for sectionIndex: Int,
15+
environment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection?
16+
}
17+
18+
public class VSCollectionViewLayoutProvider: VSCollectionViewLayoutProviderAPI {
1319

1420
unowned private var collectionView: UICollectionView
15-
unowned private var sectionHandler: VSCollectionViewSectionHandller
21+
unowned private var sectionHandler: VSCollectionViewSectionLayoutHandlerAPI
1622
public var data: VSCollectionViewData?
1723

1824
public init(collectionView: UICollectionView,
19-
sectionHandler: VSCollectionViewSectionHandller) {
25+
sectionHandler: VSCollectionViewSectionLayoutHandlerAPI) {
2026
self.collectionView = collectionView
2127
self.sectionHandler = sectionHandler
2228
}

VSCollectionKit/VSCollectionKit/VSCollectionViewController/VSCollectionViewSectionHandler.swift

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,21 @@
99
import UIKit
1010
import VSCollectionViewData
1111

12-
public class VSCollectionViewSectionHandller {
12+
public protocol VSCollectionViewSectionHandlerAPI: class {
13+
func addSectionHandler(handler: SectionHandler)
14+
func removeSectionHandler(type: String)
15+
func registerCells(for collectionView: UICollectionView)
16+
func numOfRows(for sectionModel: SectionModel, sectionIndex: Int) -> Int
17+
func cell(for collectionView: UICollectionView,
18+
indexPath: IndexPath,
19+
sectionModel: SectionModel) -> UICollectionViewCell
20+
func supplementaryView(collectionView: UICollectionView,
21+
kind: String,
22+
indexPath: IndexPath,
23+
sectionModel: SectionModel) -> UICollectionReusableView?
24+
}
25+
26+
public class VSCollectionViewSectionHandller: VSCollectionViewSectionHandlerAPI {
1327

1428
public init() {}
1529

@@ -46,47 +60,63 @@ public class VSCollectionViewSectionHandller {
4660
sectionModel.items[indexPath.row])
4761
}
4862

49-
func supplementaryView(collectionView: UICollectionView,
63+
public func supplementaryView(collectionView: UICollectionView,
5064
kind: String,
5165
indexPath: IndexPath,
5266
sectionModel: SectionModel) -> UICollectionReusableView? {
5367
guard let sectionHandler = sectionHandlers[sectionModel.sectionType],
5468
let headerViewModel = sectionModel.header else { return nil }
5569

56-
return sectionHandler.supplementaryViewProvider(collectionView,
70+
return sectionHandler.sectionHeaderFooterProvider?.supplementaryViewProvider(collectionView,
5771
kind,
5872
indexPath,
5973
headerViewModel)
6074
}
6175
}
6276

63-
extension VSCollectionViewSectionHandller {
77+
public protocol VSCollectionViewSectionLayoutHandlerAPI: class {
6478
func collectionLayout(for sectionModel: SectionModel,
79+
environment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection?
80+
}
81+
82+
extension VSCollectionViewSectionHandller: VSCollectionViewSectionLayoutHandlerAPI {
83+
84+
public func collectionLayout(for sectionModel: SectionModel,
6585
environment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? {
6686
guard let sectionHandler = sectionHandlers[sectionModel.sectionType] else { return nil }
6787
return sectionHandler.sectionLayoutProvider(sectionModel,
6888
environment)
6989
}
7090
}
7191

72-
extension VSCollectionViewSectionHandller {
73-
92+
public protocol VSCollectionViewSectionDelegateHandlerAPI: class {
7493
func willDisplayCell(collectionView: UICollectionView,
94+
indexPath: IndexPath,
95+
cell: UICollectionViewCell,
96+
sectionModel: SectionModel)
97+
func didSelectItemAt(_ collectionView: UICollectionView,
98+
indexPath: IndexPath,
99+
sectionModel: SectionModel)
100+
}
101+
102+
extension VSCollectionViewSectionHandller: VSCollectionViewSectionDelegateHandlerAPI {
103+
104+
public func willDisplayCell(collectionView: UICollectionView,
75105
indexPath: IndexPath,
76106
cell: UICollectionViewCell,
77107
sectionModel: SectionModel) {
78108
guard let sectionHandler = sectionHandlers[sectionModel.sectionType] else { return }
79-
sectionHandler.willDisplayCell(collectionView,
109+
sectionHandler.sectionDelegateHandler?.willDisplayCell(collectionView,
80110
indexPath,
81111
cell,
82112
sectionModel.items[indexPath.row])
83113
}
84114

85-
func didSelectItemAt(_ collectionView: UICollectionView,
115+
public func didSelectItemAt(_ collectionView: UICollectionView,
86116
indexPath: IndexPath,
87117
sectionModel: SectionModel) {
88118
guard let sectionHandler = sectionHandlers[sectionModel.sectionType] else { return }
89-
sectionHandler.didSelect(collectionView,
119+
sectionHandler.sectionDelegateHandler?.didSelect(collectionView,
90120
indexPath,
91121
sectionModel.items[indexPath.row])
92122
}

0 commit comments

Comments
 (0)