From ecdb1b2b710e30315c1d77ccbea961db64287c00 Mon Sep 17 00:00:00 2001 From: Thomas Van Lenten Date: Fri, 5 Aug 2016 13:58:05 -0400 Subject: Make GTMLogLevelFilter use KVO on GTMVerboseLogging in sharedUserDefaults This avoids checking if verbose logging is enabled on every user defaults change, and only does so when the verbose logging key changes. In sampling a few apps, this showed up as a hit when the app changes default (directly or via the System frameworks storing things). By using KVO for it it basically disappears from the samples. --- Foundation/GTMLogger.h | 1 + Foundation/GTMLogger.m | 45 +++++++++++++++++++++++++++++---------------- 2 files changed, 30 insertions(+), 16 deletions(-) (limited to 'Foundation') diff --git a/Foundation/GTMLogger.h b/Foundation/GTMLogger.h index a776922..16f0eaf 100644 --- a/Foundation/GTMLogger.h +++ b/Foundation/GTMLogger.h @@ -457,6 +457,7 @@ typedef enum { @interface GTMLogLevelFilter : NSObject { @private BOOL verboseLoggingEnabled_; + NSUserDefaults *userDefaults_; } @end // GTMLogLevelFilter diff --git a/Foundation/GTMLogger.m b/Foundation/GTMLogger.m index 7c2a543..3ace20f 100644 --- a/Foundation/GTMLogger.m +++ b/Foundation/GTMLogger.m @@ -97,7 +97,7 @@ static GTMLogger *gSharedLogger = nil; // Don't trust NSFileHandle not to throw @try { - GTMLogBasicFormatter *formatter = [[[GTMLogBasicFormatter alloc] init] + GTMLogBasicFormatter *formatter = [[[GTMLogBasicFormatter alloc] init] autorelease]; GTMLogger *stdoutLogger = [self loggerWithWriter:[NSFileHandle fileHandleWithStandardOutput] @@ -475,12 +475,13 @@ static GTMLogger *gSharedLogger = nil; @end // GTMLogStandardFormatter +static NSString *const kVerboseLoggingKey = @"GTMVerboseLogging"; + // Check the environment and the user preferences for the GTMVerboseLogging key // to see if verbose logging has been enabled. The environment variable will // override the defaults setting, so check the environment first. // COV_NF_START -static BOOL IsVerboseLoggingEnabled(void) { - static NSString *const kVerboseLoggingKey = @"GTMVerboseLogging"; +static BOOL IsVerboseLoggingEnabled(NSUserDefaults *userDefaults) { NSString *value = [[[NSProcessInfo processInfo] environment] objectForKey:kVerboseLoggingKey]; if (value) { @@ -495,7 +496,7 @@ static BOOL IsVerboseLoggingEnabled(void) { return NO; } } - return [[NSUserDefaults standardUserDefaults] boolForKey:kVerboseLoggingKey]; + return [userDefaults boolForKey:kVerboseLoggingKey]; } // COV_NF_END @@ -504,21 +505,28 @@ static BOOL IsVerboseLoggingEnabled(void) { - (id)init { self = [super init]; if (self) { - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(defaultsChanged:) - name:NSUserDefaultsDidChangeNotification - object:nil]; - - verboseLoggingEnabled_ = IsVerboseLoggingEnabled(); + // Keep a reference to standardUserDefaults, avoiding a crash if client code calls + // "NSUserDefaults resetStandardUserDefaults" which releases it from memory. We are still + // notified of changes through our instance. Note: resetStandardUserDefaults does not actually + // clear settings: + // https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSUserDefaults_Class/index.html#//apple_ref/occ/clm/NSUserDefaults/resetStandardUserDefaults + // and so should only be called in test code if necessary. + userDefaults_ = [[NSUserDefaults standardUserDefaults] retain]; + [userDefaults_ addObserver:self + forKeyPath:kVerboseLoggingKey + options:NSKeyValueObservingOptionNew + context:nil]; + + verboseLoggingEnabled_ = IsVerboseLoggingEnabled(userDefaults_); } return self; } - (void)dealloc { - [[NSNotificationCenter defaultCenter] removeObserver:self - name:NSUserDefaultsDidChangeNotification - object:nil]; + [userDefaults_ removeObserver:self forKeyPath:kVerboseLoggingKey]; + [userDefaults_ release]; + [super dealloc]; } @@ -552,8 +560,14 @@ static BOOL IsVerboseLoggingEnabled(void) { return allow; } -- (void)defaultsChanged:(NSNotification *)note { - verboseLoggingEnabled_ = IsVerboseLoggingEnabled(); +- (void)observeValueForKeyPath:(NSString *)keyPath + ofObject:(id)object + change:(NSDictionary *)change + context:(void *)context +{ + if([keyPath isEqual:kVerboseLoggingKey]) { + verboseLoggingEnabled_ = IsVerboseLoggingEnabled(userDefaults_); + } } @end // GTMLogLevelFilter @@ -632,4 +646,3 @@ static BOOL IsVerboseLoggingEnabled(void) { // See comment at top of file. #pragma GCC diagnostic error "-Wmissing-format-attribute" #endif // !__clang__ - -- cgit v1.2.3