diff --git a/Sources/RDReaderView/EPUBUI/ReaderController/ChapterRuntime/RDEPUBChapterWarmupOrchestrator.swift b/Sources/RDReaderView/EPUBUI/ReaderController/ChapterRuntime/RDEPUBChapterWarmupOrchestrator.swift index ad7b265..7d23fab 100644 --- a/Sources/RDReaderView/EPUBUI/ReaderController/ChapterRuntime/RDEPUBChapterWarmupOrchestrator.swift +++ b/Sources/RDReaderView/EPUBUI/ReaderController/ChapterRuntime/RDEPUBChapterWarmupOrchestrator.swift @@ -32,6 +32,8 @@ final class RDEPUBChapterWarmupOrchestrator { private let prepareRequestDebounceInterval: CFTimeInterval = 0.15 + private static let upcomingChapterLookaheadCount = 2 + init( context: RDEPUBReaderContext, store: RDEPUBChapterRuntimeStore, @@ -392,7 +394,10 @@ final class RDEPUBChapterWarmupOrchestrator { windowRadius: context.configuration.chapterWindowRadius ) - for evictable in store.evictableSpineIndices() { + // Keep chapters that maybePrefetchUpcomingChapters is responsible for, + // otherwise the two policies evict/rebuild the same chapter in a loop. + let retainedLookaheadIndices = upcomingLookaheadSpineIndices(after: spineIndex) + for evictable in store.evictableSpineIndices() where !retainedLookaheadIndices.contains(evictable) { store.evict(spineIndex: evictable) } @@ -410,11 +415,18 @@ final class RDEPUBChapterWarmupOrchestrator { } } + private func upcomingLookaheadSpineIndices(after spineIndex: Int) -> Set { + guard let publication = context.publication else { return [] } + let buildableIndices = buildableSpineIndices(in: publication) + guard let currentPosition = buildableIndices.firstIndex(of: spineIndex) else { return [] } + return Set(buildableIndices.dropFirst(currentPosition + 1).prefix(Self.upcomingChapterLookaheadCount)) + } + private func maybePrefetchUpcomingChapters( aroundAbsolutePageNumber pageNumber: Int, in bookPageMap: RDEPUBBookPageMap, threshold: Int = 3, - lookaheadChapterCount: Int = 2 + lookaheadChapterCount: Int = RDEPUBChapterWarmupOrchestrator.upcomingChapterLookaheadCount ) { guard let publication = context.publication else { return } let absolutePageIndex = pageNumber - 1