Create and use PostponingBlock.
This commit is contained in:
parent
0d36face00
commit
74a42c6f3e
@ -21,20 +21,24 @@ public protocol DataFileDelegate: AnyObject {
|
||||
private var isDirty = false {
|
||||
didSet {
|
||||
if isDirty {
|
||||
restartTimer()
|
||||
postponingBlock.runInFuture()
|
||||
}
|
||||
else {
|
||||
invalidateTimer()
|
||||
postponingBlock.cancelRun()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private let fileURL: URL
|
||||
private let saveInterval: TimeInterval = 1.0
|
||||
private var timer: Timer?
|
||||
|
||||
private lazy var postponingBlock: PostponingBlock = {
|
||||
PostponingBlock(delayInterval: 1.0) { [weak self] in
|
||||
self?.saveToDiskIfNeeded()
|
||||
}
|
||||
}()
|
||||
|
||||
public init(fileURL: URL) {
|
||||
|
||||
|
||||
self.fileURL = fileURL
|
||||
}
|
||||
|
||||
@ -64,33 +68,8 @@ private extension DataFile {
|
||||
|
||||
func saveToDiskIfNeeded() {
|
||||
|
||||
assert(Thread.isMainThread)
|
||||
|
||||
if isDirty {
|
||||
save()
|
||||
}
|
||||
}
|
||||
|
||||
func restartTimer() {
|
||||
|
||||
assert(Thread.isMainThread)
|
||||
|
||||
invalidateTimer()
|
||||
|
||||
timer = Timer.scheduledTimer(withTimeInterval: saveInterval, repeats: false) { timer in
|
||||
MainActor.assumeIsolated {
|
||||
self.saveToDiskIfNeeded()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func invalidateTimer() {
|
||||
|
||||
assert(Thread.isMainThread)
|
||||
|
||||
if let timer, timer.isValid {
|
||||
timer.invalidate()
|
||||
}
|
||||
timer = nil
|
||||
}
|
||||
}
|
||||
|
51
Core/Sources/Core/PostponingBlock.swift
Normal file
51
Core/Sources/Core/PostponingBlock.swift
Normal file
@ -0,0 +1,51 @@
|
||||
//
|
||||
// PostponingBlock.swift
|
||||
//
|
||||
//
|
||||
// Created by Brent Simmons on 6/9/24.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/// Runs a block of code in the future. Each time `runInFuture` is called, the block is postponed again until the future by `delayInterval`.
|
||||
@MainActor public final class PostponingBlock {
|
||||
|
||||
private let block: () -> Void
|
||||
private let delayInterval: TimeInterval
|
||||
private var timer: Timer?
|
||||
|
||||
public init(delayInterval: TimeInterval, block: @escaping () -> Void) {
|
||||
|
||||
self.block = block
|
||||
self.delayInterval = delayInterval
|
||||
}
|
||||
|
||||
/// Run the block in `delayInterval` seconds, canceling any run about to happen before then.
|
||||
public func runInFuture() {
|
||||
|
||||
invalidateTimer()
|
||||
|
||||
timer = Timer.scheduledTimer(withTimeInterval: delayInterval, repeats: false) { timer in
|
||||
MainActor.assumeIsolated {
|
||||
self.block()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Cancel any upcoming run.
|
||||
public func cancelRun() {
|
||||
|
||||
invalidateTimer()
|
||||
}
|
||||
}
|
||||
|
||||
private extension PostponingBlock {
|
||||
|
||||
func invalidateTimer() {
|
||||
|
||||
if let timer, timer.isValid {
|
||||
timer.invalidate()
|
||||
}
|
||||
timer = nil
|
||||
}
|
||||
}
|
@ -48,6 +48,15 @@ final class SmartFeed: PseudoFeed {
|
||||
}
|
||||
#endif
|
||||
|
||||
private lazy var postponingBlock: PostponingBlock = {
|
||||
PostponingBlock(delayInterval: 1.0) {
|
||||
Task {
|
||||
try? await self.fetchUnreadCounts()
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
private var fetchUnreadCountsTask: Task<Void, Never>?
|
||||
private let delegate: SmartFeedDelegate
|
||||
private var unreadCounts = [String: Int]()
|
||||
|
||||
@ -63,7 +72,7 @@ final class SmartFeed: PseudoFeed {
|
||||
}
|
||||
}
|
||||
|
||||
@MainActor @objc func fetchUnreadCounts() {
|
||||
@MainActor func fetchUnreadCounts() async throws {
|
||||
|
||||
let activeAccounts = AccountManager.shared.activeAccounts
|
||||
|
||||
@ -79,11 +88,9 @@ final class SmartFeed: PseudoFeed {
|
||||
updateUnreadCount()
|
||||
return
|
||||
}
|
||||
|
||||
Task { @MainActor in
|
||||
for account in activeAccounts {
|
||||
await fetchUnreadCount(for: account)
|
||||
}
|
||||
|
||||
for account in activeAccounts {
|
||||
await fetchUnreadCount(for: account)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -104,7 +111,8 @@ extension SmartFeed: ArticleFetcher {
|
||||
private extension SmartFeed {
|
||||
|
||||
@MainActor func queueFetchUnreadCounts() {
|
||||
CoalescingQueue.standard.add(self, #selector(fetchUnreadCounts))
|
||||
|
||||
postponingBlock.runInFuture()
|
||||
}
|
||||
|
||||
@MainActor func fetchUnreadCount(for account: Account) async {
|
||||
@ -125,3 +133,4 @@ private extension SmartFeed {
|
||||
unreadCount = unread
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user