Move item count fetching to background task

This commit is contained in:
Shadowfacts 2022-09-10 00:09:46 -04:00
parent c12b9ae879
commit 6bb292ba13
3 changed files with 54 additions and 11 deletions

View File

@ -9,7 +9,7 @@ import Foundation
import CoreData
import Persistence
enum ItemListType: Hashable {
enum ItemListType: Hashable, Equatable {
case unread
case all
case group(Group)
@ -52,7 +52,9 @@ enum ItemListType: Hashable {
case .all:
return nil
case .group(let group):
req.predicate = NSPredicate(format: "read = NO AND feed in %@", group.feeds!)
// use the feed ids, because passing the NSSet of feeds into the predicate results in a multithreading violation if the request is used on a different context
let feedIDs = group.feeds!.map { ($0 as! Feed).objectID }
req.predicate = NSPredicate(format: "read = NO AND feed in %@", feedIDs)
case .feed(let feed):
req.predicate = NSPredicate(format: "read = NO AND feed = %@", feed)
}

View File

@ -7,9 +7,16 @@
import UIKit
import Fervor
import Persistence
import OSLog
private let signposter = OSSignposter(subsystem: "net.shadowfacts.Reader", category: "HomeCollectionViewCell")
class HomeCollectionViewCell: UICollectionViewListCell {
private var currentItemListType: ItemListType?
private var itemCount: Int?
#if !targetEnvironment(macCatalyst)
override func updateConfiguration(using state: UICellConfigurationState) {
var backgroundConfig = UIBackgroundConfiguration.listGroupedCell().updated(for: state)
@ -22,4 +29,45 @@ class HomeCollectionViewCell: UICollectionViewListCell {
}
#endif
override func prepareForReuse() {
super.prepareForReuse()
itemCount = nil
}
func updateUI(item: ItemListType, persistentContainer: PersistentContainer) {
self.currentItemListType = item
var config = UIListContentConfiguration.valueCell()
config.text = item.title
if let itemCount {
config.secondaryText = itemCount.formatted(.number)
}
config.secondaryTextProperties.color = .tintColor
self.contentConfiguration = config
Task(priority: .userInitiated) {
let state = signposter.beginInterval("fetch count", id: signposter.makeSignpostID())
if let count = await fetchCount(item: item, in: persistentContainer),
self.currentItemListType == item {
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 context = persistentContainer.backgroundContext
context.perform {
let count = try? context.count(for: request)
continuation.resume(returning: count)
}
})
}
}

View File

@ -126,15 +126,8 @@ class HomeViewController: UIViewController {
config.text = section.title
supplementaryView.contentConfiguration = config
}
let listCell = UICollectionView.CellRegistration<HomeCollectionViewCell, ItemListType> { cell, indexPath, item in
var config = UIListContentConfiguration.valueCell()
config.text = item.title
if let req = item.countFetchRequest,
let count = try? self.fervorController.persistentContainer.viewContext.count(for: req) {
config.secondaryText = "\(count)"
config.secondaryTextProperties.color = .tintColor
}
cell.contentConfiguration = config
let listCell = UICollectionView.CellRegistration<HomeCollectionViewCell, ItemListType> { [unowned self] cell, indexPath, item in
cell.updateUI(item: item, persistentContainer: self.fervorController.persistentContainer)
cell.accessories = [.disclosureIndicator()]
}