Skip to content

Commit 2569c66

Browse files
Fix possible conflict with default Reuse Identifiers (#154)
Closes #150. - Fixed a (potential) bug where cells with the same name, but in different modules, would provide the same (conflicting) default `reuseIdentifier`. Default `reuseIdentifiers` now return the fully qualified type name. - Previous behavior: `"MyCellClassName"` - New behavior: `"MyModuleName.MyCellClassName"` - **Note:** This should be a transparent change and not impact any existing code. If you were previously working around this issue by providing a custom `reuseIdentifier`, you can now adopt the default implementation instead. --------- Co-authored-by: Copilot <[email protected]>
1 parent 07194ec commit 2569c66

8 files changed

+193
-181
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,15 @@ The changelog for `ReactiveCollectionsKit`. Also see [the releases on GitHub](ht
55
NEXT
66
-----
77

8+
- TBA
9+
10+
0.1.9
11+
-----
12+
13+
- Fixed a (potential) bug where cells with the same name, but in different modules, would provide the same (conflicting) default `reuseIdentifier`. Default `reuseIdentifiers` now return the fully qualified type name. ([@jessesquires](https://github.com/jessesquires), [#150](https://github.com/jessesquires/ReactiveCollectionsKit/issues/150), [#154](https://github.com/jessesquires/ReactiveCollectionsKit/pull/154))
14+
- Previous behavior: `"MyCellClassName"`
15+
- New behavior: `"MyModuleName.MyCellClassName"`
16+
- **Note:** This should be a transparent change and not impact any existing code. If you were previously working around this issue by providing a custom `reuseIdentifier`, you can now adopt the default implementation instead.
817
- Improve debug descriptions (i.e., `CustomDebugStringConvertible`) for various types. ([@nuomi1](https://github.com/nuomi1), [#139](https://github.com/jessesquires/ReactiveCollectionsKit/pull/139))
918
- Implement (optional) debug logging for view model updates. You can now provide a logger for debugging purposes by setting `CollectionViewDriver.logger`. The library provides a default implementation via `RCKLogger.shared`. ([@nuomi1](https://github.com/nuomi1), [#141](https://github.com/jessesquires/ReactiveCollectionsKit/pull/141))
1019
- Upgrade to Xcode 26. ([@jessesquires](https://github.com/jessesquires), [#153](https://github.com/jessesquires/ReactiveCollectionsKit/pull/153))

Sources/CellViewModel.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,8 +139,8 @@ extension CellViewModel {
139139
public var cellClass: AnyClass { CellType.self }
140140

141141
/// A default reuse identifier for cell registration.
142-
/// Returns the name of the class implementing the `CellViewModel` protocol.
143-
public var reuseIdentifier: String { "\(Self.self)" }
142+
/// Returns the fully qualified type name (module name + class name) of the class implementing the `CellViewModel` protocol.
143+
public var reuseIdentifier: String { String(reflecting: Self.self) }
144144

145145
/// A default registration for this view model for class-based cells.
146146
/// - Warning: Does not work for nib-based cells.

Sources/SupplementaryViewModel.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@ extension SupplementaryViewModel {
6161
public var viewClass: AnyClass { ViewType.self }
6262

6363
/// A default reuse identifier for cell registration.
64-
/// Returns the name of the class implementing the `CellViewModel` protocol.
65-
public var reuseIdentifier: String { "\(Self.self)" }
64+
/// Returns the fully qualified type name (module name + class name) of the class implementing the `SupplementaryViewModel` protocol.
65+
public var reuseIdentifier: String { String(reflecting: Self.self) }
6666

6767
/// Returns a type-erased version of this view model.
6868
public func eraseToAnyViewModel() -> AnySupplementaryViewModel {

Tests/TestCellViewModel.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,12 @@ final class TestCellViewModel: XCTestCase {
3535
func test_CellViewModel_protocol_extension() {
3636
let viewModel = FakeCellViewModel()
3737
XCTAssert(viewModel.cellClass == FakeCollectionCell.self)
38-
XCTAssertEqual(viewModel.reuseIdentifier, "FakeCellViewModel")
38+
XCTAssertEqual(viewModel.reuseIdentifier, "ReactiveCollectionsKitTests.FakeCellViewModel")
3939

40-
let expected = ViewRegistration(reuseIdentifier: "FakeCellViewModel", cellClass: FakeCollectionCell.self)
40+
let expected = ViewRegistration(
41+
reuseIdentifier: "ReactiveCollectionsKitTests.FakeCellViewModel",
42+
cellClass: FakeCollectionCell.self
43+
)
4144
XCTAssertEqual(viewModel.registration, expected)
4245
}
4346

Tests/TestDebugDescriptionCollection.swift

Lines changed: 117 additions & 117 deletions
Large diffs are not rendered by default.

Tests/TestDebugDescriptionDriver.swift

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -103,18 +103,18 @@ final class TestDebugDescriptionDriver: XCTestCase {
103103
sections:
104104
\\[0\\]:
105105
id: section_0
106-
header: Header \\(FakeHeaderViewModel\\)
107-
footer: Footer \\(FakeFooterViewModel\\)
106+
header: Header \\(ReactiveCollectionsKitTests.FakeHeaderViewModel\\)
107+
footer: Footer \\(ReactiveCollectionsKitTests.FakeFooterViewModel\\)
108108
cells:
109-
\\[0\\]: cell_0_0 \\(FakeNumberCellViewModel\\)
109+
\\[0\\]: cell_0_0 \\(ReactiveCollectionsKitTests.FakeNumberCellViewModel\\)
110110
supplementary views:
111-
\\[0\\]: view_0_0 \\(FakeSupplementaryViewModel\\)
111+
\\[0\\]: view_0_0 \\(ReactiveCollectionsKitTests.FakeSupplementaryViewModel\\)
112112
isEmpty: false
113113
registrations:
114-
- FakeFooterViewModel \\(UICollectionElementKindSectionFooter\\)
115-
- FakeHeaderViewModel \\(UICollectionElementKindSectionHeader\\)
116-
- FakeNumberCellViewModel \\(cell\\)
117-
- FakeSupplementaryViewModel \\(FakeKind\\)
114+
- ReactiveCollectionsKitTests.FakeFooterViewModel \\(UICollectionElementKindSectionFooter\\)
115+
- ReactiveCollectionsKitTests.FakeHeaderViewModel \\(UICollectionElementKindSectionHeader\\)
116+
- ReactiveCollectionsKitTests.FakeNumberCellViewModel \\(cell\\)
117+
- ReactiveCollectionsKitTests.FakeSupplementaryViewModel \\(FakeKind\\)
118118
isEmpty: false
119119
\\}
120120
emptyViewProvider: nil

Tests/TestDebugDescriptionSection.swift

Lines changed: 47 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,10 @@ final class TestDebugDescriptionSection: XCTestCase {
5353
header: nil
5454
footer: nil
5555
cells:
56-
[0]: cell_0_0 (FakeNumberCellViewModel)
56+
[0]: cell_0_0 (ReactiveCollectionsKitTests.FakeNumberCellViewModel)
5757
supplementary views: none
5858
registrations:
59-
- FakeNumberCellViewModel (cell)
59+
- ReactiveCollectionsKitTests.FakeNumberCellViewModel (cell)
6060
isEmpty: false
6161
}
6262
"""
@@ -77,13 +77,13 @@ final class TestDebugDescriptionSection: XCTestCase {
7777
header: nil
7878
footer: nil
7979
cells:
80-
[0]: cell_0_0 (FakeNumberCellViewModel)
81-
[1]: cell_0_1 (FakeTextCellViewModel)
82-
[2]: cell_0_2 (FakeNumberCellViewModel)
80+
[0]: cell_0_0 (ReactiveCollectionsKitTests.FakeNumberCellViewModel)
81+
[1]: cell_0_1 (ReactiveCollectionsKitTests.FakeTextCellViewModel)
82+
[2]: cell_0_2 (ReactiveCollectionsKitTests.FakeNumberCellViewModel)
8383
supplementary views: none
8484
registrations:
85-
- FakeNumberCellViewModel (cell)
86-
- FakeTextCellViewModel (cell)
85+
- ReactiveCollectionsKitTests.FakeNumberCellViewModel (cell)
86+
- ReactiveCollectionsKitTests.FakeTextCellViewModel (cell)
8787
isEmpty: false
8888
}
8989
"""
@@ -102,12 +102,12 @@ final class TestDebugDescriptionSection: XCTestCase {
102102
header: nil
103103
footer: nil
104104
cells:
105-
[0]: cell_0_0 (FakeCellNibViewModel)
106-
[1]: cell_0_1 (FakeCellNibViewModel)
107-
[2]: cell_0_2 (FakeCellNibViewModel)
105+
[0]: cell_0_0 (ReactiveCollectionsKitTests.FakeCellNibViewModel)
106+
[1]: cell_0_1 (ReactiveCollectionsKitTests.FakeCellNibViewModel)
107+
[2]: cell_0_2 (ReactiveCollectionsKitTests.FakeCellNibViewModel)
108108
supplementary views: none
109109
registrations:
110-
- FakeCellNibViewModel (cell)
110+
- ReactiveCollectionsKitTests.FakeCellNibViewModel (cell)
111111
isEmpty: false
112112
}
113113
"""
@@ -126,17 +126,17 @@ final class TestDebugDescriptionSection: XCTestCase {
126126
"""
127127
SectionViewModel {
128128
id: viewModel_6
129-
header: Header (FakeHeaderViewModel)
129+
header: Header (ReactiveCollectionsKitTests.FakeHeaderViewModel)
130130
footer: nil
131131
cells:
132-
[0]: cell_0_0 (FakeNumberCellViewModel)
133-
[1]: cell_0_1 (FakeTextCellViewModel)
134-
[2]: cell_0_2 (FakeNumberCellViewModel)
132+
[0]: cell_0_0 (ReactiveCollectionsKitTests.FakeNumberCellViewModel)
133+
[1]: cell_0_1 (ReactiveCollectionsKitTests.FakeTextCellViewModel)
134+
[2]: cell_0_2 (ReactiveCollectionsKitTests.FakeNumberCellViewModel)
135135
supplementary views: none
136136
registrations:
137-
- FakeHeaderViewModel (UICollectionElementKindSectionHeader)
138-
- FakeNumberCellViewModel (cell)
139-
- FakeTextCellViewModel (cell)
137+
- ReactiveCollectionsKitTests.FakeHeaderViewModel (UICollectionElementKindSectionHeader)
138+
- ReactiveCollectionsKitTests.FakeNumberCellViewModel (cell)
139+
- ReactiveCollectionsKitTests.FakeTextCellViewModel (cell)
140140
isEmpty: false
141141
}
142142
"""
@@ -153,16 +153,16 @@ final class TestDebugDescriptionSection: XCTestCase {
153153
SectionViewModel {
154154
id: viewModel_7
155155
header: nil
156-
footer: Footer (FakeFooterViewModel)
156+
footer: Footer (ReactiveCollectionsKitTests.FakeFooterViewModel)
157157
cells:
158-
[0]: cell_0_0 (FakeNumberCellViewModel)
159-
[1]: cell_0_1 (FakeTextCellViewModel)
160-
[2]: cell_0_2 (FakeNumberCellViewModel)
158+
[0]: cell_0_0 (ReactiveCollectionsKitTests.FakeNumberCellViewModel)
159+
[1]: cell_0_1 (ReactiveCollectionsKitTests.FakeTextCellViewModel)
160+
[2]: cell_0_2 (ReactiveCollectionsKitTests.FakeNumberCellViewModel)
161161
supplementary views: none
162162
registrations:
163-
- FakeFooterViewModel (UICollectionElementKindSectionFooter)
164-
- FakeNumberCellViewModel (cell)
165-
- FakeTextCellViewModel (cell)
163+
- ReactiveCollectionsKitTests.FakeFooterViewModel (UICollectionElementKindSectionFooter)
164+
- ReactiveCollectionsKitTests.FakeNumberCellViewModel (cell)
165+
- ReactiveCollectionsKitTests.FakeTextCellViewModel (cell)
166166
isEmpty: false
167167
}
168168
"""
@@ -179,18 +179,18 @@ final class TestDebugDescriptionSection: XCTestCase {
179179
"""
180180
SectionViewModel {
181181
id: viewModel_8
182-
header: Header (FakeHeaderViewModel)
183-
footer: Footer (FakeFooterViewModel)
182+
header: Header (ReactiveCollectionsKitTests.FakeHeaderViewModel)
183+
footer: Footer (ReactiveCollectionsKitTests.FakeFooterViewModel)
184184
cells:
185-
[0]: cell_0_0 (FakeNumberCellViewModel)
186-
[1]: cell_0_1 (FakeTextCellViewModel)
187-
[2]: cell_0_2 (FakeNumberCellViewModel)
185+
[0]: cell_0_0 (ReactiveCollectionsKitTests.FakeNumberCellViewModel)
186+
[1]: cell_0_1 (ReactiveCollectionsKitTests.FakeTextCellViewModel)
187+
[2]: cell_0_2 (ReactiveCollectionsKitTests.FakeNumberCellViewModel)
188188
supplementary views: none
189189
registrations:
190-
- FakeFooterViewModel (UICollectionElementKindSectionFooter)
191-
- FakeHeaderViewModel (UICollectionElementKindSectionHeader)
192-
- FakeNumberCellViewModel (cell)
193-
- FakeTextCellViewModel (cell)
190+
- ReactiveCollectionsKitTests.FakeFooterViewModel (UICollectionElementKindSectionFooter)
191+
- ReactiveCollectionsKitTests.FakeHeaderViewModel (UICollectionElementKindSectionHeader)
192+
- ReactiveCollectionsKitTests.FakeNumberCellViewModel (cell)
193+
- ReactiveCollectionsKitTests.FakeTextCellViewModel (cell)
194194
isEmpty: false
195195
}
196196
"""
@@ -208,22 +208,22 @@ final class TestDebugDescriptionSection: XCTestCase {
208208
"""
209209
SectionViewModel {
210210
id: viewModel_9
211-
header: Header (FakeHeaderViewModel)
212-
footer: Footer (FakeFooterViewModel)
211+
header: Header (ReactiveCollectionsKitTests.FakeHeaderViewModel)
212+
footer: Footer (ReactiveCollectionsKitTests.FakeFooterViewModel)
213213
cells:
214-
[0]: cell_0_0 (FakeNumberCellViewModel)
215-
[1]: cell_0_1 (FakeTextCellViewModel)
216-
[2]: cell_0_2 (FakeNumberCellViewModel)
214+
[0]: cell_0_0 (ReactiveCollectionsKitTests.FakeNumberCellViewModel)
215+
[1]: cell_0_1 (ReactiveCollectionsKitTests.FakeTextCellViewModel)
216+
[2]: cell_0_2 (ReactiveCollectionsKitTests.FakeNumberCellViewModel)
217217
supplementary views:
218-
[0]: view_0_0 (FakeSupplementaryViewModel)
219-
[1]: view_0_1 (FakeSupplementaryViewModel)
220-
[2]: view_0_2 (FakeSupplementaryViewModel)
218+
[0]: view_0_0 (ReactiveCollectionsKitTests.FakeSupplementaryViewModel)
219+
[1]: view_0_1 (ReactiveCollectionsKitTests.FakeSupplementaryViewModel)
220+
[2]: view_0_2 (ReactiveCollectionsKitTests.FakeSupplementaryViewModel)
221221
registrations:
222-
- FakeFooterViewModel (UICollectionElementKindSectionFooter)
223-
- FakeHeaderViewModel (UICollectionElementKindSectionHeader)
224-
- FakeNumberCellViewModel (cell)
225-
- FakeSupplementaryViewModel (FakeKind)
226-
- FakeTextCellViewModel (cell)
222+
- ReactiveCollectionsKitTests.FakeFooterViewModel (UICollectionElementKindSectionFooter)
223+
- ReactiveCollectionsKitTests.FakeHeaderViewModel (UICollectionElementKindSectionHeader)
224+
- ReactiveCollectionsKitTests.FakeNumberCellViewModel (cell)
225+
- ReactiveCollectionsKitTests.FakeSupplementaryViewModel (FakeKind)
226+
- ReactiveCollectionsKitTests.FakeTextCellViewModel (cell)
227227
isEmpty: false
228228
}
229229
"""

Tests/TestSupplementaryViewModel.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ final class TestSupplementaryViewModel: XCTestCase {
2121
func test_SupplementaryViewModel_protocol_extension() {
2222
let viewModel = FakeSupplementaryViewModel()
2323
XCTAssert(viewModel.viewClass == FakeSupplementaryView.self)
24-
XCTAssertEqual(viewModel.reuseIdentifier, "FakeSupplementaryViewModel")
24+
XCTAssertEqual(viewModel.reuseIdentifier, "ReactiveCollectionsKitTests.FakeSupplementaryViewModel")
2525
}
2626

2727
// swiftlint:disable xct_specific_matcher
@@ -101,7 +101,7 @@ final class TestSupplementaryViewModel: XCTestCase {
101101
XCTAssertEqual(viewModel._kind, UICollectionView.elementKindSectionHeader)
102102

103103
let expected = ViewRegistration(
104-
reuseIdentifier: "FakeHeaderViewModel",
104+
reuseIdentifier: "ReactiveCollectionsKitTests.FakeHeaderViewModel",
105105
supplementaryViewClass: FakeCollectionHeaderView.self,
106106
kind: UICollectionView.elementKindSectionHeader
107107
)
@@ -116,7 +116,7 @@ final class TestSupplementaryViewModel: XCTestCase {
116116
XCTAssertEqual(viewModel._kind, UICollectionView.elementKindSectionFooter)
117117

118118
let expected = ViewRegistration(
119-
reuseIdentifier: "FakeFooterViewModel",
119+
reuseIdentifier: "ReactiveCollectionsKitTests.FakeFooterViewModel",
120120
supplementaryViewClass: FakeCollectionFooterView.self,
121121
kind: UICollectionView.elementKindSectionFooter
122122
)

0 commit comments

Comments
 (0)