From 35df7fa9b8d83fd24a25e42302721593c8d57a3e Mon Sep 17 00:00:00 2001 From: Eitot Date: Wed, 10 May 2023 21:33:04 +0200 Subject: [PATCH] Add ObserverContext to KVO handlers Apple recommends using an address of a static variable as a context pointer to filter out unrelated observer callbacks. If the context is unrelated then the callback should be passed on to the super class. https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/KeyValueObserving/Articles/KVOBasics.html --- Vienna/Sources/Application/AppController.m | 18 +++++++++++++++--- Vienna/Sources/Main window/ArticleController.m | 18 +++++++++++++++--- Vienna/Sources/Main window/ArticleListView.m | 12 ++++++------ Vienna/Sources/Main window/FolderView.m | 2 -- Vienna/Sources/Main window/FoldersTree.m | 12 ++++++------ .../Sources/Main window/UnifiedDisplayView.m | 18 +++++++++++++++--- 6 files changed, 57 insertions(+), 23 deletions(-) diff --git a/Vienna/Sources/Application/AppController.m b/Vienna/Sources/Application/AppController.m index 52485a9673..f59b28f661 100644 --- a/Vienna/Sources/Application/AppController.m +++ b/Vienna/Sources/Application/AppController.m @@ -61,6 +61,8 @@ #define VNA_LOG os_log_create("--", "AppController") +static void *VNAAppControllerObserverContext = &VNAAppControllerObserverContext; + @interface AppController () -(void)installScriptsFolderWatcher; @@ -295,7 +297,7 @@ -(void)applicationDidFinishLaunching:(NSNotification *)aNot [self.pluginManager addObserver:self forKeyPath:NSStringFromSelector(@selector(numberOfPlugins)) options:0 - context:nil]; + context:VNAAppControllerObserverContext]; // Load the styles into the main menu. [self populateStyleMenu]; @@ -1223,7 +1225,16 @@ - (void)populatePluginsMenu { - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change - context:(void *)context { + context:(void *)context +{ + if (context != VNAAppControllerObserverContext) { + [super observeValueForKeyPath:keyPath + ofObject:object + change:change + context:context]; + return; + } + if ([keyPath isEqualToString:NSStringFromSelector(@selector(numberOfPlugins))]) { NSMenu *menu = ((ViennaApp *)NSApp).articleMenu; @@ -3571,7 +3582,8 @@ - (FoldersTree *)foldersTree { -(void)dealloc { [self.pluginManager removeObserver:self - forKeyPath:NSStringFromSelector(@selector(numberOfPlugins))]; + forKeyPath:NSStringFromSelector(@selector(numberOfPlugins)) + context:VNAAppControllerObserverContext]; [[NSNotificationCenter defaultCenter] removeObserver:self]; } diff --git a/Vienna/Sources/Main window/ArticleController.m b/Vienna/Sources/Main window/ArticleController.m index a918f92320..5b08b10b2a 100644 --- a/Vienna/Sources/Main window/ArticleController.m +++ b/Vienna/Sources/Main window/ArticleController.m @@ -39,6 +39,8 @@ #define VNA_LOG os_log_create("--", "ArticleController") +static void *VNAArticleControllerObserverContext = &VNAArticleControllerObserverContext; + @interface ArticleController () -(NSArray *)applyFilter:(NSArray *)unfilteredArray; @@ -131,7 +133,7 @@ -(instancetype)init [NSUserDefaults.standardUserDefaults addObserver:self forKeyPath:MAPref_FilterMode options:0 - context:nil]; + context:VNAArticleControllerObserverContext]; queue = dispatch_queue_create("uk.co.opencommunity.vienna2.displayRefresh", DISPATCH_QUEUE_SERIAL); requireSelectArticleAfterReload = NO; @@ -1146,7 +1148,16 @@ - (BOOL)filterArticle:(Article *)article usingMode:(NSInteger)filterMode { - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change - context:(void *)context { + context:(void *)context +{ + if (context != VNAArticleControllerObserverContext) { + [super observeValueForKeyPath:keyPath + ofObject:object + change:change + context:context]; + return; + } + if ([keyPath isEqualToString:MAPref_FilterMode]) { // Update the list of articles when the user changes the filter. @synchronized(mainArticleView) { @@ -1158,7 +1169,8 @@ - (void)observeValueForKeyPath:(NSString *)keyPath - (void)dealloc { [NSNotificationCenter.defaultCenter removeObserver:self]; [NSUserDefaults.standardUserDefaults removeObserver:self - forKeyPath:MAPref_FilterMode]; + forKeyPath:MAPref_FilterMode + context:VNAArticleControllerObserverContext]; } @end diff --git a/Vienna/Sources/Main window/ArticleListView.m b/Vienna/Sources/Main window/ArticleListView.m index 074a6f5ed9..821f3201a6 100644 --- a/Vienna/Sources/Main window/ArticleListView.m +++ b/Vienna/Sources/Main window/ArticleListView.m @@ -42,7 +42,7 @@ // Shared defaults key NSString * const MAPref_ShowEnclosureBar = @"ShowEnclosureBar"; -static void *ObserverContext = &ObserverContext; +static void *VNAArticleListViewObserverContext = &VNAArticleListViewObserverContext; @interface ArticleListView () @@ -182,11 +182,11 @@ -(void)initialiseArticleView [userDefaults addObserver:self forKeyPath:MAPref_ShowEnclosureBar options:NSKeyValueObservingOptionNew - context:ObserverContext]; + context:VNAArticleListViewObserverContext]; [userDefaults addObserver:self forKeyPath:MAPref_ShowUnreadArticlesInBold options:0 - context:ObserverContext]; + context:VNAArticleListViewObserverContext]; } /* initTableView @@ -1651,10 +1651,10 @@ -(void)dealloc NSUserDefaults *userDefaults = NSUserDefaults.standardUserDefaults; [userDefaults removeObserver:self forKeyPath:MAPref_ShowEnclosureBar - context:ObserverContext]; + context:VNAArticleListViewObserverContext]; [userDefaults removeObserver:self forKeyPath:MAPref_ShowUnreadArticlesInBold - context:ObserverContext]; + context:VNAArticleListViewObserverContext]; [splitView2 setDelegate:nil]; [articleList setDelegate:nil]; } @@ -1666,7 +1666,7 @@ - (void)observeValueForKeyPath:(NSString *)keyPath change:(NSDictionary *)change context:(void *)context { - if (context != ObserverContext) { + if (context != VNAArticleListViewObserverContext) { [super observeValueForKeyPath:keyPath ofObject:object change:change diff --git a/Vienna/Sources/Main window/FolderView.m b/Vienna/Sources/Main window/FolderView.m index 3729f0d91a..8d81cdf260 100644 --- a/Vienna/Sources/Main window/FolderView.m +++ b/Vienna/Sources/Main window/FolderView.m @@ -33,8 +33,6 @@ VNAFeedListRowHeight const VNAFeedListRowHeightSmall = 24.0; VNAFeedListRowHeight const VNAFeedListRowHeightMedium = 28.0; -static void *ObserverContext = &ObserverContext; - @interface FolderView () @property (weak, nonatomic) IBOutlet NSView *floatingResetButtonView; diff --git a/Vienna/Sources/Main window/FoldersTree.m b/Vienna/Sources/Main window/FoldersTree.m index ba2a181c6e..94fcc8ffbf 100644 --- a/Vienna/Sources/Main window/FoldersTree.m +++ b/Vienna/Sources/Main window/FoldersTree.m @@ -37,7 +37,7 @@ NSString * const MAPref_FeedListSizeMode = @"FeedListSizeMode"; NSString * const MAPref_ShowFeedsWithUnreadItemsInBold = @"ShowFeedsWithUnreadItemsInBold"; -static void *ObserverContext = &ObserverContext; +static void *VNAFoldersTreeObserverContext = &VNAFoldersTreeObserverContext; @interface FoldersTree () @@ -122,11 +122,11 @@ -(void)initialiseFoldersTree [userDefaults addObserver:self forKeyPath:MAPref_FeedListSizeMode options:0 - context:ObserverContext]; + context:VNAFoldersTreeObserverContext]; [userDefaults addObserver:self forKeyPath:MAPref_ShowFeedsWithUnreadItemsInBold options:0 - context:ObserverContext]; + context:VNAFoldersTreeObserverContext]; } - (void)dealloc @@ -136,10 +136,10 @@ - (void)dealloc NSUserDefaults *userDefaults; [userDefaults removeObserver:self forKeyPath:MAPref_FeedListSizeMode - context:ObserverContext]; + context:VNAFoldersTreeObserverContext]; [userDefaults removeObserver:self forKeyPath:MAPref_ShowFeedsWithUnreadItemsInBold - context:ObserverContext]; + context:VNAFoldersTreeObserverContext]; } -(void)handleOpenReaderFolderChange:(NSNotification *)nc @@ -1105,7 +1105,7 @@ - (void)observeValueForKeyPath:(NSString *)keyPath change:(NSDictionary *)change context:(void *)context { - if (context != ObserverContext) { + if (context != VNAFoldersTreeObserverContext) { [super observeValueForKeyPath:keyPath ofObject:object change:change diff --git a/Vienna/Sources/Main window/UnifiedDisplayView.m b/Vienna/Sources/Main window/UnifiedDisplayView.m index 489d3da68e..2b8084ebc6 100644 --- a/Vienna/Sources/Main window/UnifiedDisplayView.m +++ b/Vienna/Sources/Main window/UnifiedDisplayView.m @@ -40,6 +40,8 @@ #define YPOS_IN_CELL 2.0 #define PROGRESS_INDICATOR_DIMENSION 16 +static void *VNAUnifiedDisplayViewObserverContext = &VNAUnifiedDisplayViewObserverContext; + @interface UnifiedDisplayView () @property (nonatomic) OverlayStatusBar *statusBar; @@ -144,7 +146,7 @@ -(void)initTableView [NSUserDefaults.standardUserDefaults addObserver:self forKeyPath:MAPref_ShowStatusBar options:NSKeyValueObservingOptionInitial - context:nil]; + context:VNAUnifiedDisplayViewObserverContext]; } /* dealloc @@ -153,7 +155,8 @@ -(void)initTableView -(void)dealloc { [NSUserDefaults.standardUserDefaults removeObserver:self - forKeyPath:MAPref_ShowStatusBar]; + forKeyPath:MAPref_ShowStatusBar + context:VNAUnifiedDisplayViewObserverContext]; [[NSNotificationCenter defaultCenter] removeObserver:self]; [articleList setDataSource:nil]; [articleList setDelegate:nil]; @@ -813,7 +816,16 @@ -(void)keyDown:(NSEvent *)theEvent - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change - context:(void *)context { + context:(void *)context +{ + if (context != VNAUnifiedDisplayViewObserverContext) { + [super observeValueForKeyPath:keyPath + ofObject:object + change:change + context:context]; + return; + } + if ([keyPath isEqualToString:MAPref_ShowStatusBar]) { BOOL isStatusBarShown = [Preferences standardPreferences].showStatusBar; if (isStatusBarShown && !self.statusBar) {