feat: EPUB阅读器搜索、注释、CFI模块及大书远距跳转优化

- 实现EPUB阅读器搜索功能及选中注释功能
- 优化CFI模块,修复代码审查发现的11个问题
- 实现大书远距目录跳转与后台补全优化方案
- 优化设置面板与章节运行时联动
- 重构及大量改进优化
This commit is contained in:
shenlei
2026-06-22 20:26:34 +08:00
parent f50495ad91
commit c65c190b71
178 changed files with 11380 additions and 6728 deletions
@@ -2,50 +2,36 @@ import UIKit
final class RDEPUBChapterRuntimeStore {
// MARK: -
/// WXRead chapterDataCache
private let chapterDataCache = RDEPUBChapterDataCache()
/// WXRead pageCountCache
private let pageCountCache = RDEPUBPageCountCache()
/// NSCache WXRead imageCache
let imageCache = NSCache<NSString, UIImage>()
/// WXRead com.weread.chapterload
/// QoS .userInitiated/
let chapterLoadQueue = DispatchQueue(label: "com.rdreader.chapterload", qos: .userInitiated)
private let chapterLoadQueueKey = DispatchSpecificKey<Void>()
// MARK: -
/// spineIndex
private(set) var currentSpineIndex: Int?
/// spineIndex
private(set) var windowSpineIndices: [Int] = []
// MARK: - vs
/// ///
///
private var pendingNavigationTarget: Int?
private let navigationLock = NSLock()
/// ±1
///
private var pendingPrefetchTargets: Set<Int> = []
private let prefetchLock = NSLock()
///
private(set) var isBuilding: Bool = false
private let buildingLock = NSLock()
// MARK: -
init() {
imageCache.countLimit = 50
chapterLoadQueue.setSpecific(key: chapterLoadQueueKey, value: ())
}
@@ -53,8 +39,6 @@ final class RDEPUBChapterRuntimeStore {
dispatchPrecondition(condition: .notOnQueue(chapterLoadQueue))
}
// MARK: - 线 cache wrapper lock
func chapterData(for spineIndex: Int) -> RDEPUBRuntimeChapter? {
return chapterDataCache[spineIndex]
}
@@ -63,8 +47,6 @@ final class RDEPUBChapterRuntimeStore {
return pageCountCache[key]
}
// MARK: -
func insertChapter(_ chapter: RDEPUBRuntimeChapter) {
chapterDataCache[chapter.spineIndex] = chapter
}
@@ -73,9 +55,6 @@ final class RDEPUBChapterRuntimeStore {
pageCountCache[key] = pc
}
// MARK: -
///
func setCurrentChapter(spineIndex: Int, totalSpineCount: Int, windowRadius: Int = 1) {
currentSpineIndex = spineIndex
let radius = max(0, windowRadius)
@@ -88,14 +67,11 @@ final class RDEPUBChapterRuntimeStore {
windowSpineIndices = Array(lowerBound...upperBound)
}
/// spineIndex
func evictableSpineIndices() -> [Int] {
let windowSet = Set(windowSpineIndices)
return chapterDataCache.storedSpineIndices.filter { !windowSet.contains($0) }
}
// MARK: -
func evict(spineIndex: Int) {
chapterDataCache.remove(spineIndex: spineIndex)
pageCountCache.remove(forSpineIndex: spineIndex)
@@ -112,28 +88,21 @@ final class RDEPUBChapterRuntimeStore {
if let ch = currentChapter {
chapterDataCache[current] = ch
}
// WXRead pageCountCache
pageCountCache.removeAll()
}
// MARK: -
func handleMemoryWarning() {
evictAllExceptCurrent()
imageCache.removeAllObjects()
}
// MARK: - §14.4
///
///
func setNavigationTarget(spineIndex: Int) {
navigationLock.lock()
pendingNavigationTarget = spineIndex
navigationLock.unlock()
}
///
func consumeNavigationTarget() -> Int? {
navigationLock.lock()
let target = pendingNavigationTarget
@@ -142,31 +111,24 @@ final class RDEPUBChapterRuntimeStore {
return target
}
// MARK: -
/// ±1
///
func addPrefetchTarget(_ spineIndex: Int) {
prefetchLock.lock()
pendingPrefetchTargets.insert(spineIndex)
prefetchLock.unlock()
}
///
func removePrefetchTarget(_ spineIndex: Int) {
prefetchLock.lock()
pendingPrefetchTargets.remove(spineIndex)
prefetchLock.unlock()
}
///
func clearPrefetchTargets() {
prefetchLock.lock()
pendingPrefetchTargets.removeAll()
prefetchLock.unlock()
}
///
func hasPrefetchTarget(_ spineIndex: Int) -> Bool {
prefetchLock.lock()
let has = pendingPrefetchTargets.contains(spineIndex)
@@ -180,8 +142,6 @@ final class RDEPUBChapterRuntimeStore {
buildingLock.unlock()
}
// MARK: - P1: §8.5
func invalidateAllForSettingsChange() {
chapterDataCache.removeAll()
pageCountCache.removeAll()