From 987c178c35739a6eed0ed372e1fbbd2419879bb6 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Mon, 2 Nov 2020 19:03:23 -0500 Subject: [PATCH] Review changes for kvo cleanliness --- .../MVMCoreAlertHandler+Extension.swift | 29 +++++++--- MVMCoreUI/TopAlert/MVMCoreTopAlertOperation.h | 6 +-- MVMCoreUI/TopAlert/MVMCoreTopAlertOperation.m | 54 +++++++++++-------- 3 files changed, 56 insertions(+), 33 deletions(-) diff --git a/MVMCoreUI/Alerts/MVMCoreAlertHandler+Extension.swift b/MVMCoreUI/Alerts/MVMCoreAlertHandler+Extension.swift index 364ee6cb..a2a8f665 100644 --- a/MVMCoreUI/Alerts/MVMCoreAlertHandler+Extension.swift +++ b/MVMCoreUI/Alerts/MVMCoreAlertHandler+Extension.swift @@ -12,19 +12,19 @@ public extension MVMCoreAlertHandler { /// Re-evaluates the queue operations @objc func reevaluteQueue() { - var highestReadyOperation: MVMCoreTopAlertOperation? + var higherPriorityOperationIsReady = false var executingOperation: MVMCoreTopAlertOperation? + let pageType = (MVMCoreUISplitViewController.main()?.getCurrentDetailViewController() as? MVMCoreViewControllerProtocol)?.pageType let sortedOperations = topAlertQueue.operations.sorted { $0.queuePriority.rawValue > $1.queuePriority.rawValue } for case let operation as MVMCoreTopAlertOperation in sortedOperations { guard !operation.isCancelled, !operation.isFinished else { continue } - operation.refreshReady() - if operation.isReady, - highestReadyOperation == nil { - highestReadyOperation = operation - } + updatePageReadiness(for: operation, with: pageType) if operation.isExecuting { executingOperation = operation + } else if operation.isReady, + executingOperation == nil { + higherPriorityOperationIsReady = true } } guard let currentOperation = executingOperation else { return } @@ -37,8 +37,7 @@ public extension MVMCoreAlertHandler { } // If the highest priority operation is not executing, and the executing operation is persistent, cancel it. - if let newOperation = highestReadyOperation, - currentOperation != newOperation, + if higherPriorityOperationIsReady, currentOperation.topAlertObject.persistent { currentOperation.reAddAfterCancel = true currentOperation.cancel() @@ -50,6 +49,20 @@ public extension MVMCoreAlertHandler { NotificationCenter.default.addObserver(self, selector: #selector(viewControllerChanged(notification:)), name: NSNotification.Name(rawValue: MVMCoreNotificationViewControllerChanged), object: nil) } + /// Updates the operation isDisplayable based on the page type. + private func updatePageReadiness(for topOperation: MVMCoreTopAlertOperation, with pageType: String?) { + guard let pages = topOperation.topAlertObject.json?.optionalArrayForKey("pages") as? [String], + pages.count != 0 else { + topOperation.isDisplayable = true + return + } + guard let pageType = pageType else { + topOperation.isDisplayable = false + return + } + topOperation.isDisplayable = pages.contains(pageType) + } + /// When a detail page changes, check top alerts. @objc private func viewControllerChanged(notification: Notification) { reevaluteQueue() diff --git a/MVMCoreUI/TopAlert/MVMCoreTopAlertOperation.h b/MVMCoreUI/TopAlert/MVMCoreTopAlertOperation.h index 86831e89..16f2ab8d 100644 --- a/MVMCoreUI/TopAlert/MVMCoreTopAlertOperation.h +++ b/MVMCoreUI/TopAlert/MVMCoreTopAlertOperation.h @@ -15,6 +15,9 @@ @property (readonly, getter=isPaused) BOOL paused; +/// A bool for if this top alert can be displayed. It is only ready if true. +@property (nonatomic, getter=isDisplayable) BOOL displayable; + @property (nonatomic) BOOL reAddAfterCancel; @property (nonnull, nonatomic, strong) MVMCoreTopAlertObject *topAlertObject; @@ -30,7 +33,4 @@ // Unpauses the operation, resuming any alert. - (void)unpause; -// NSOperationQueue uses KVO, this forces it to aknowledge changes -- (void)refreshReady; - @end diff --git a/MVMCoreUI/TopAlert/MVMCoreTopAlertOperation.m b/MVMCoreUI/TopAlert/MVMCoreTopAlertOperation.m index f721734a..a59248ab 100644 --- a/MVMCoreUI/TopAlert/MVMCoreTopAlertOperation.m +++ b/MVMCoreUI/TopAlert/MVMCoreTopAlertOperation.m @@ -16,6 +16,7 @@ __block BOOL _paused; __block BOOL _displayed; __block BOOL _animating; + __block BOOL _displayable; } @property (readwrite, getter=isPaused) BOOL paused; @@ -26,6 +27,7 @@ @property (strong, nonatomic) dispatch_queue_t pausedQueue; @property (strong, nonatomic) dispatch_queue_t displayedQueue; @property (strong, nonatomic) dispatch_queue_t animatingQueue; +@property (strong, nonatomic) dispatch_queue_t displayableQueue; @property (nonatomic, strong) dispatch_source_t timerSource; @@ -40,6 +42,8 @@ self.pausedQueue = dispatch_queue_create("paused", DISPATCH_QUEUE_CONCURRENT); self.displayedQueue = dispatch_queue_create("displayed", DISPATCH_QUEUE_CONCURRENT); self.animatingQueue = dispatch_queue_create("animating", DISPATCH_QUEUE_CONCURRENT); + self.displayableQueue = dispatch_queue_create("displayable", DISPATCH_QUEUE_CONCURRENT); + self.displayable = YES; } return self; } @@ -109,25 +113,35 @@ }); } -// Ensure the current page is supported for this top alert. + +- (BOOL)isDisplayable { + __block BOOL isDisplayable; + dispatch_sync(self.displayableQueue, ^{ + isDisplayable = self->_displayable; + }); + return isDisplayable; +} + +- (void)setDisplayable:(BOOL)displayable { + if (displayable != self.isDisplayable) { + BOOL isReady = [super isReady]; + if (isReady) { + [self willChangeValueForKey:@"isReady"]; + } + dispatch_barrier_async(self.displayableQueue, ^{ + self->_displayable = displayable; + }); + if (isReady) { + [self didChangeValueForKey:@"isReady"]; + } + } +} + - (BOOL)isReady { - BOOL isReady = [super isReady]; - if (self.isCancelled || self.isFinished) { - return isReady; + if (self.isCancelled) { + return [super isReady]; } - - NSArray *pages = [self.topAlertObject.json array:@"pages"]; - if (pages.count == 0) { - return isReady; - } - - UIViewController *detailViewController = [[MVMCoreUISplitViewController mainSplitViewController] getCurrentDetailViewController]; - if (![detailViewController conformsToProtocol:@protocol(MVMCoreViewControllerProtocol)]) { - return isReady; - } - - NSString *pageType = ((UIViewController *)detailViewController).pageType; - return isReady && [pages containsObject:pageType]; + return [super isReady] && self.isDisplayable; } - (void)main { @@ -254,11 +268,6 @@ } } -- (void)refreshReady { - [self willChangeValueForKey:@"isReady"]; - [self didChangeValueForKey:@"isReady"]; -} - #pragma mark - Delegate functions - (void)topAlertViewBeginAnimation { @@ -278,6 +287,7 @@ copyObject.topAlertObject = self.topAlertObject; copyObject.paused = self.paused; copyObject.reAddAfterCancel = self.reAddAfterCancel; + copyObject.displayable = self.isDisplayable; copyObject.queuePriority = self.queuePriority; for (NSOperation *dependency in self.dependencies) { [copyObject addDependency:dependency];