Shadowfacts
6881441671
A significant fraction of the time was spent waiting for the background context to be available, before the count could even be started. Since the counts don't need to use the shared background context, let them each use their own context to avoid contention.
76 lines
2.9 KiB
Swift
76 lines
2.9 KiB
Swift
//
|
|
// HomeCollectionViewCell.swift
|
|
// Reader
|
|
//
|
|
// Created by Shadowfacts on 1/9/22.
|
|
//
|
|
|
|
import UIKit
|
|
import Fervor
|
|
import Persistence
|
|
import OSLog
|
|
|
|
private let signposter = OSSignposter(subsystem: "net.shadowfacts.Reader", category: "HomeCollectionViewCell")
|
|
|
|
class HomeCollectionViewCell: UICollectionViewListCell {
|
|
|
|
private var currentItemCountTask: Task<Void, Never>?
|
|
private var itemCount: Int?
|
|
|
|
#if !targetEnvironment(macCatalyst)
|
|
override func updateConfiguration(using state: UICellConfigurationState) {
|
|
var backgroundConfig = UIBackgroundConfiguration.listGroupedCell().updated(for: state)
|
|
if state.isHighlighted || state.isSelected {
|
|
backgroundConfig.backgroundColor = .appCellHighlightBackground
|
|
} else {
|
|
backgroundConfig.backgroundColor = .appBackground
|
|
}
|
|
self.backgroundConfiguration = backgroundConfig
|
|
}
|
|
#endif
|
|
|
|
override func prepareForReuse() {
|
|
super.prepareForReuse()
|
|
currentItemCountTask?.cancel()
|
|
itemCount = nil
|
|
}
|
|
|
|
func updateUI(item: ItemListType, persistentContainer: PersistentContainer) {
|
|
var config = UIListContentConfiguration.valueCell()
|
|
config.text = item.title
|
|
if let itemCount {
|
|
config.secondaryText = itemCount.formatted(.number)
|
|
}
|
|
config.secondaryTextProperties.color = .tintColor
|
|
self.contentConfiguration = config
|
|
|
|
currentItemCountTask = Task(priority: .userInitiated) {
|
|
let state = signposter.beginInterval("fetch count", id: signposter.makeSignpostID(), "\(String(item.hashValue, radix: 16), privacy: .public)")
|
|
if let count = await fetchCount(item: item, in: persistentContainer),
|
|
!Task.isCancelled {
|
|
self.itemCount = count
|
|
config.secondaryText = count.formatted(.number)
|
|
self.contentConfiguration = config
|
|
}
|
|
signposter.endInterval("fetch count", state)
|
|
}
|
|
}
|
|
|
|
private func fetchCount(item: ItemListType, in persistentContainer: PersistentContainer) async -> Int? {
|
|
guard let request = item.countFetchRequest else {
|
|
return nil
|
|
}
|
|
return await withCheckedContinuation({ continuation in
|
|
let state = signposter.beginInterval("waiting to perform", id: signposter.makeSignpostID(), "\(String(item.hashValue, radix: 16), privacy: .public)")
|
|
persistentContainer.performBackgroundTask { context in
|
|
signposter.endInterval("waiting to perform", state)
|
|
let state = signposter.beginInterval("count", id: signposter.makeSignpostID(), "\(String(item.hashValue, radix: 16), privacy: .public)")
|
|
let count = try? context.count(for: request)
|
|
signposter.endInterval("count", state)
|
|
continuation.resume(returning: count)
|
|
}
|
|
})
|
|
}
|
|
|
|
}
|