Skip to content

Commit 376b8ea

Browse files
author
Eugene Kazaev
committed
Minor performance improvements
1 parent 8ac42fa commit 376b8ea

File tree

2 files changed

+47
-16
lines changed

2 files changed

+47
-16
lines changed

ChatLayout.podspec

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Pod::Spec.new do |s|
22
s.name = 'ChatLayout'
3-
s.version = '1.1.10'
3+
s.version = '1.1.11'
44
s.summary = 'Chat UI Library. It uses custom UICollectionViewLayout to provide you full control over the presentation.'
55
s.swift_version = '5.2'
66

ChatLayout/Classes/Core/Model/StateController.swift

+46-15
Original file line numberDiff line numberDiff line change
@@ -620,7 +620,6 @@ final class StateController {
620620
var allRects = [(frame: CGRect, indexPath: ItemPath, kind: ItemKind)]()
621621
// I dont think there can be more then a 200 elements on the screen simultaneously
622622
allRects.reserveCapacity(200)
623-
let skipIndex = 100
624623
for sectionIndex in 0..<layout.sections.count {
625624
let section = layout.sections[sectionIndex]
626625
let sectionPath = ItemPath(item: 0, section: sectionIndex)
@@ -632,22 +631,33 @@ final class StateController {
632631
break
633632
}
634633

635-
var startingIndex = 0
636-
// Lets try to skip some calculations as visible rect most often is at the bottom of the layout
637-
if traverseState == .notFound {
638-
var iterationIndex = skipIndex
639-
while iterationIndex < section.items.count {
640-
let itemPath = ItemPath(item: iterationIndex, section: sectionIndex)
641-
let itemFrame = self.itemFrame(for: itemPath, kind: .cell, at: state, isFinal: true)
642-
if itemFrame == nil || itemFrame.map({ $0.maxY < visibleRect.minY ? true : false }) == true {
643-
startingIndex = iterationIndex
644-
iterationIndex += skipIndex
645-
continue
646-
} else {
647-
break
648-
}
634+
guard let firstMatchIndex = Array(section.items.enumerated()).binarySearch(predicate: { itemIndex, _ in
635+
let itemPath = ItemPath(item: itemIndex, section: sectionIndex)
636+
guard let itemFrame = self.itemFrame(for: itemPath, kind: .cell, at: state, isFinal: true) else {
637+
return .orderedDescending
638+
}
639+
if itemFrame.intersects(visibleRect) {
640+
return .orderedSame
641+
}
642+
if itemFrame.minY > visibleRect.maxY {
643+
return .orderedDescending
644+
}
645+
return .orderedAscending
646+
}) else {
647+
break
648+
}
649+
var startingIndex = firstMatchIndex
650+
for itemIndex in (0..<firstMatchIndex).reversed() {
651+
let itemPath = ItemPath(item: itemIndex, section: sectionIndex)
652+
guard let itemFrame = itemFrame(for: itemPath, kind: .cell, at: state, isFinal: true) else {
653+
continue
654+
}
655+
guard itemFrame.maxY >= visibleRect.minY else {
656+
break
649657
}
658+
startingIndex = itemIndex
650659
}
660+
651661
if startingIndex < section.items.count {
652662
for itemIndex in startingIndex..<section.items.count {
653663
let itemPath = ItemPath(item: itemIndex, section: sectionIndex)
@@ -813,3 +823,24 @@ final class StateController {
813823
}
814824

815825
}
826+
827+
private extension RandomAccessCollection where Index == Int {
828+
829+
func binarySearch(predicate: (Element) -> ComparisonResult) -> Index? {
830+
var lowerBound = startIndex
831+
var upperBound = endIndex
832+
833+
while lowerBound < upperBound {
834+
let midIndex = lowerBound + (upperBound - lowerBound) / 2
835+
if predicate(self[midIndex]) == .orderedSame {
836+
return midIndex
837+
} else if predicate(self[midIndex]) == .orderedAscending {
838+
lowerBound = midIndex + 1
839+
} else {
840+
upperBound = midIndex
841+
}
842+
}
843+
return nil
844+
}
845+
846+
}

0 commit comments

Comments
 (0)