From ebdd758b144377c3fab8183499b4008e4d9af934 Mon Sep 17 00:00:00 2001 From: Winston Du Date: Thu, 20 Feb 2020 16:28:07 -0800 Subject: [PATCH 1/3] Add update and move support --- Sources/Internal/DiffableDataSourceCore.swift | 4 ++-- Sources/Internal/SnapshotStructure.swift | 14 ++++++++------ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/Sources/Internal/DiffableDataSourceCore.swift b/Sources/Internal/DiffableDataSourceCore.swift index b45b757..a401bf4 100644 --- a/Sources/Internal/DiffableDataSourceCore.swift +++ b/Sources/Internal/DiffableDataSourceCore.swift @@ -68,7 +68,7 @@ final class DiffableDataSourceCore ItemIdentifierType { @@ -83,7 +83,7 @@ final class DiffableDataSourceCore { struct Item: Differentiable, Equatable { - var differenceIdentifier: ItemID + var differenceIdentifier: Int + var identifier: ItemID var isReloaded: Bool init(id: ItemID, isReloaded: Bool) { - self.differenceIdentifier = id + self.identifier = id + self.differenceIdentifier = id.hashValue self.isReloaded = isReloaded } @@ -16,7 +18,7 @@ struct SnapshotStructure { } func isContentEqual(to source: Item) -> Bool { - return !isReloaded && differenceIdentifier == source.differenceIdentifier + return !isReloaded && identifier == source.identifier } } @@ -53,7 +55,7 @@ struct SnapshotStructure { var allItemIDs: [ItemID] { return sections.lazy .flatMap { $0.elements } - .map { $0.differenceIdentifier } + .map { $0.identifier } } func items(in sectionID: SectionID, file: StaticString = #file, line: UInt = #line) -> [ItemID] { @@ -61,7 +63,7 @@ struct SnapshotStructure { specifiedSectionIsNotFound(sectionID, file: file, line: line) } - return sections[sectionIndex].elements.map { $0.differenceIdentifier } + return sections[sectionIndex].elements.map { $0.identifier } } func section(containing itemID: ItemID) -> SectionID? { @@ -270,7 +272,7 @@ private extension SnapshotStructure { func itemPositionMap() -> [ItemID: ItemPosition] { return sections.enumerated().reduce(into: [:]) { result, section in for (itemRelativeIndex, item) in section.element.elements.enumerated() { - result[item.differenceIdentifier] = ItemPosition( + result[item.identifier] = ItemPosition( item: item, itemRelativeIndex: itemRelativeIndex, section: section.element, From 067f69cac76b054cd740cd316cd182eac1b362c2 Mon Sep 17 00:00:00 2001 From: Winston Du Date: Thu, 20 Feb 2020 17:11:46 -0800 Subject: [PATCH 2/3] Add example --- .../Example-iOS/MountainsViewController.swift | 28 +++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/Examples/Example-iOS/MountainsViewController.swift b/Examples/Example-iOS/MountainsViewController.swift index 5806939..7e3b5f9 100644 --- a/Examples/Example-iOS/MountainsViewController.swift +++ b/Examples/Example-iOS/MountainsViewController.swift @@ -8,6 +8,11 @@ final class MountainsViewController: UIViewController { struct Mountain: Hashable { var name: String + var highlightedName: NSAttributedString + + func hash(into hasher: inout Hasher) { + hasher.combine(name) + } func contains(_ filter: String) -> Bool { guard !filter.isEmpty else { @@ -24,13 +29,13 @@ final class MountainsViewController: UIViewController { private lazy var dataSource = CollectionViewDiffableDataSource(collectionView: collectionView) { collectionView, indexPath, mountain in let cell = collectionView.dequeueReusableCell(withReuseIdentifier: LabelCell.name, for: indexPath) as! LabelCell - cell.label.text = mountain.name + cell.label.attributedText = mountain.highlightedName return cell } private let allMountains: [Mountain] = mountainsRawData.components(separatedBy: .newlines).map { line in let name = line.components(separatedBy: ",")[0] - return Mountain(name: name) + return Mountain(name: name, highlightedName: NSAttributedString(string: name)) } override func viewDidLoad() { @@ -49,6 +54,10 @@ final class MountainsViewController: UIViewController { let mountains = allMountains.lazy .filter { $0.contains(filter) } .sorted { $0.name < $1.name } + .map { mountain -> Mountain in + let attrName = underlineOccurences(of: filter.lowercased(), in: NSMutableAttributedString(string: mountain.name)) + return Mountain(name: mountain.name, highlightedName: attrName) + } var snapshot = DiffableDataSourceSnapshot() snapshot.appendSections([.main]) @@ -57,6 +66,21 @@ final class MountainsViewController: UIViewController { } } +private func underlineOccurences(of searchString: String, in text: NSMutableAttributedString) -> NSMutableAttributedString { + let inputLength = text.string.count + let searchLength = searchString.count + var range = NSRange(location: 0, length: text.length) + + while range.location != NSNotFound { + range = (text.string.lowercased() as NSString).range(of: searchString, options: [], range: range) + if range.location != NSNotFound { + text.addAttribute(NSAttributedString.Key.underlineStyle, value: NSUnderlineStyle.single.rawValue, range: NSRange(location: range.location, length: searchLength)) + range = NSRange(location: range.location + range.length, length: inputLength - (range.location + range.length)) + } + } + return text +} + extension MountainsViewController: UISearchBarDelegate { func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) { search(filter: searchText) From f4f20c30117634a75b213e30e0855c0d3804cc52 Mon Sep 17 00:00:00 2001 From: Winston Du Date: Thu, 27 Feb 2020 15:10:39 -0800 Subject: [PATCH 3/3] Slight rename to reduce confusion --- Sources/Internal/DiffableDataSourceCore.swift | 4 ++-- Sources/Internal/SnapshotStructure.swift | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Sources/Internal/DiffableDataSourceCore.swift b/Sources/Internal/DiffableDataSourceCore.swift index a401bf4..a95e877 100644 --- a/Sources/Internal/DiffableDataSourceCore.swift +++ b/Sources/Internal/DiffableDataSourceCore.swift @@ -68,7 +68,7 @@ final class DiffableDataSourceCore ItemIdentifierType { @@ -83,7 +83,7 @@ final class DiffableDataSourceCore { struct Item: Differentiable, Equatable { var differenceIdentifier: Int - var identifier: ItemID + var contentIdentifier: ItemID var isReloaded: Bool init(id: ItemID, isReloaded: Bool) { - self.identifier = id + self.contentIdentifier = id self.differenceIdentifier = id.hashValue self.isReloaded = isReloaded } @@ -18,7 +18,7 @@ struct SnapshotStructure { } func isContentEqual(to source: Item) -> Bool { - return !isReloaded && identifier == source.identifier + return !isReloaded && contentIdentifier == source.contentIdentifier } } @@ -55,7 +55,7 @@ struct SnapshotStructure { var allItemIDs: [ItemID] { return sections.lazy .flatMap { $0.elements } - .map { $0.identifier } + .map { $0.contentIdentifier } } func items(in sectionID: SectionID, file: StaticString = #file, line: UInt = #line) -> [ItemID] { @@ -63,7 +63,7 @@ struct SnapshotStructure { specifiedSectionIsNotFound(sectionID, file: file, line: line) } - return sections[sectionIndex].elements.map { $0.identifier } + return sections[sectionIndex].elements.map { $0.contentIdentifier } } func section(containing itemID: ItemID) -> SectionID? { @@ -272,7 +272,7 @@ private extension SnapshotStructure { func itemPositionMap() -> [ItemID: ItemPosition] { return sections.enumerated().reduce(into: [:]) { result, section in for (itemRelativeIndex, item) in section.element.elements.enumerated() { - result[item.identifier] = ItemPosition( + result[item.contentIdentifier] = ItemPosition( item: item, itemRelativeIndex: itemRelativeIndex, section: section.element,