Go back to CoalescingQueue because it was simpler to use than PostponingBlock.

This commit is contained in:
Brent Simmons 2024-06-12 20:55:13 -07:00
parent 7dc0d6cb23
commit 308a91cf4f
6 changed files with 41 additions and 113 deletions

View File

@ -21,25 +21,18 @@ public protocol DataFileDelegate: AnyObject {
private var isDirty = false {
didSet {
if isDirty {
postponingBlock.runInFuture()
}
else {
postponingBlock.cancelRun()
saveQueue.add(self, #selector(saveToDiskIfNeeded))
}
}
}
private let fileURL: URL
private lazy var postponingBlock: PostponingBlock = {
PostponingBlock(name: "DataFile \(fileURL.absoluteString)", delayInterval: 1.0) { [weak self] in
self?.saveToDiskIfNeeded()
}
}()
private let saveQueue: CoalescingQueue
public init(fileURL: URL) {
self.fileURL = fileURL
self.saveQueue = CoalescingQueue(name: "DataFile \(fileURL.absoluteString)", interval: 1.0, maxInterval: 2.0)
}
public func markAsDirty() {
@ -66,7 +59,7 @@ public protocol DataFileDelegate: AnyObject {
private extension DataFile {
func saveToDiskIfNeeded() {
@objc func saveToDiskIfNeeded() {
if isDirty {
save()

View File

@ -1,59 +0,0 @@
//
// PostponingBlock.swift
//
//
// Created by Brent Simmons on 6/9/24.
//
import Foundation
import os
/// 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 {
public static let delayIntervalForUI: TimeInterval = 0.05
private let block: @MainActor () -> Void
private let delayInterval: TimeInterval
private let name: String // For debugging
private var timer: Timer?
private let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "PostponingBlock")
public init(name: String, delayInterval: TimeInterval = PostponingBlock.delayIntervalForUI, block: @MainActor @escaping () -> Void) {
self.delayInterval = delayInterval
self.name = name
self.block = block
}
/// 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) { [weak self] 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()
logger.info("Canceling existing timer in PostponingBlock: \(self.name)")
}
timer = nil
}
}

View File

@ -70,10 +70,6 @@ import Sparkle
@IBOutlet var groupArticlesByFeedMenuItem: NSMenuItem!
@IBOutlet var checkForUpdatesMenuItem: NSMenuItem!
private lazy var postponingUpdateDockBadgeBlock: PostponingBlock = {
PostponingBlock(name: "Update Dock Badge", delayInterval: 0.05, block: updateDockBadge)
}()
var unreadCount = 0 {
didSet {
if unreadCount != oldValue {
@ -542,10 +538,11 @@ import Sparkle
// MARK: - Dock Badge
func queueUpdateDockBadge() {
postponingUpdateDockBadgeBlock.runInFuture()
CoalescingQueue.standard.add(self, #selector(updateDockBadge))
}
func updateDockBadge() {
@objc func updateDockBadge() {
let label = unreadCount > 0 ? "\(unreadCount)" : ""
NSApplication.shared.dockTile.badgeLabel = label
}

View File

@ -60,12 +60,6 @@ final class MainWindowController : NSWindowController, NSUserInterfaceValidation
private var searchSmartFeed: SmartFeed? = nil
private var restoreArticleWindowScrollY: CGFloat?
private lazy var postponingMakeToolbarValidateBlock: PostponingBlock = {
PostponingBlock(name: "Make Toolbar Validate") { [weak self] in
self?.makeToolbarValidate()
}
}()
// MARK: - NSWindowController
override func windowDidLoad() {
@ -203,10 +197,10 @@ final class MainWindowController : NSWindowController, NSUserInterfaceValidation
func queueMakeToolbarValidate() {
postponingMakeToolbarValidateBlock.runInFuture()
CoalescingQueue.standard.add(self, #selector(makeToolbarValidate))
}
func makeToolbarValidate() {
@objc func makeToolbarValidate() {
window?.toolbar?.validateVisibleItems()
}

View File

@ -23,9 +23,10 @@ final class SidebarStatusBarView: NSView {
private var progress: CombinedRefreshProgress? = nil {
didSet {
CoalescingQueue.standard.add(self, #selector(updateUI))
queueUpdateUI()
}
}
override var isFlipped: Bool {
return true
}
@ -42,6 +43,11 @@ final class SidebarStatusBarView: NSView {
NotificationCenter.default.addObserver(self, selector: #selector(progressDidChange(_:)), name: .AccountRefreshProgressDidChange, object: nil)
}
func queueUpdateUI() {
CoalescingQueue.standard.add(self, #selector(updateUI))
}
@objc func updateUI() {
guard let progress = progress else {

View File

@ -48,13 +48,7 @@ import Images
}
#endif
private lazy var postponingBlock: PostponingBlock = {
PostponingBlock(name: "SmartFeed", delayInterval: 1.0) {
Task {
try? await self.fetchUnreadCounts()
}
}
}()
private let fetchUnreadCountsQueue = CoalescingQueue(name: "SmartFeed", interval: 1.0, maxInterval: 2.0)
private var fetchUnreadCountsTask: Task<Void, Never>?
private let delegate: SmartFeedDelegate
@ -71,7 +65,9 @@ import Images
queueFetchUnreadCounts()
}
func fetchUnreadCounts() async throws {
@objc func fetchUnreadCounts() {
Task {
let activeAccounts = AccountManager.shared.activeAccounts
@ -93,6 +89,7 @@ import Images
}
}
}
}
extension SmartFeed: ArticleFetcher {
@ -111,7 +108,7 @@ private extension SmartFeed {
func queueFetchUnreadCounts() {
postponingBlock.runInFuture()
fetchUnreadCountsQueue.add(self, #selector(fetchUnreadCounts))
}
func fetchUnreadCount(for account: Account) async {