2727// See comment in header.
2828#import " GTMNSObject+KeyValueObserving.h"
2929
30- #import < libkern/OSAtomic.h>
3130#include < objc/runtime.h>
32- #import < stdatomic.h>
3331
3432#import " GTMDefines.h"
3533#import " GTMDebugSelectorValidation.h"
@@ -64,11 +62,10 @@ - (id)dictionaryKeyForObserver:(id)observer
6462@end
6563
6664@interface GTMKeyValueObservingHelper : NSObject {
67- @private
68- GTM_WEAK id observer_;
65+ __weak id observer_;
6966 SEL selector_;
7067 id userInfo_;
71- GTM_WEAK id target_;
68+ __weak id target_;
7269 NSString * keyPath_;
7370}
7471
@@ -106,10 +103,10 @@ - (instancetype)initWithObserver:(id)observer
106103 if ((self = [super init ])) {
107104 observer_ = observer;
108105 selector_ = selector;
109- userInfo_ = [ userInfo retain ] ;
106+ userInfo_ = userInfo;
110107
111108 target_ = target;
112- keyPath_ = [ keyPath retain ] ;
109+ keyPath_ = keyPath;
113110
114111 [target addObserver: self
115112 forKeyPath: keyPath
@@ -131,9 +128,6 @@ - (void)dealloc {
131128 _GTMDevLog (@" Didn't deregister %@ " , self);
132129 [self deregister ];
133130 }
134- [userInfo_ release ];
135- [keyPath_ release ];
136- [super dealloc ];
137131}
138132
139133- (void )observeValueForKeyPath : (NSString *)keyPath
@@ -146,8 +140,11 @@ - (void)observeValueForKeyPath:(NSString *)keyPath
146140 ofObject: object
147141 userInfo: userInfo_
148142 change: change];
143+ #pragma clang diagnostic push
144+ #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
145+ // We are good here because the selector should not return anything.
149146 [observer_ performSelector: selector_ withObject: notification];
150- [notification release ];
147+ # pragma clang diagnostic pop
151148 } else {
152149 // COV_NF_START
153150 // There's no way this should ever be called.
@@ -163,26 +160,20 @@ - (void)observeValueForKeyPath:(NSString *)keyPath
163160- (void )deregister {
164161 [target_ removeObserver: self forKeyPath: keyPath_];
165162 target_ = nil ;
163+ observer_ = nil ;
166164}
167165
168166@end
169167
170168@implementation GTMKeyValueObservingCenter
171169
172170+ (instancetype )defaultCenter {
173- static _Atomic (GTMKeyValueObservingCenter *)center = nil ;
174- if (!center) {
175- // do a bit of clever atomic setting to make this thread safe
176- // if two threads try to set simultaneously, one will fail
177- // and the other will set things up so that the failing thread
178- // gets the shared center
179- GTMKeyValueObservingCenter *newCenter = [[self alloc ] init ];
180- GTMKeyValueObservingCenter *expected = nil ;
181- if (!atomic_compare_exchange_strong (¢er, &expected, newCenter)) {
182- [newCenter release ]; // COV_NF_LINE no guarantee we'll hit this line
183- }
184- }
185- return center;
171+ static dispatch_once_t onceToken;
172+ static GTMKeyValueObservingCenter *center;
173+ dispatch_once (&onceToken, ^{
174+ center = [[self alloc ] init ];
175+ });
176+ return center;
186177}
187178
188179- (instancetype )init {
@@ -192,14 +183,6 @@ - (instancetype)init {
192183 return self;
193184}
194185
195- // COV_NF_START
196- // Singletons don't get deallocated
197- - (void )dealloc {
198- [observerHelpers_ release ];
199- [super dealloc ];
200- }
201- // COV_NF_END
202-
203186- (id )dictionaryKeyForObserver : (id )observer
204187 ofObject : (id )target
205188 forKeyPath : (NSString *)keyPath
@@ -240,7 +223,6 @@ - (void)addObserver:(id)observer
240223 }
241224 [observerHelpers_ setObject: helper forKey: key];
242225 }
243- [helper release ];
244226}
245227
246228- (void )removeObserver : (id )observer
@@ -338,21 +320,13 @@ - (instancetype)initWithKeyPath:(NSString *)keyPath
338320 change : (NSDictionary *)change {
339321 if ((self = [super init ])) {
340322 keyPath_ = [keyPath copy ];
341- object_ = [ object retain ] ;
342- userInfo_ = [ userInfo retain ] ;
343- change_ = [ change retain ] ;
323+ object_ = object;
324+ userInfo_ = userInfo;
325+ change_ = change;
344326 }
345327 return self;
346328}
347329
348- - (void )dealloc {
349- [keyPath_ release ];
350- [object_ release ];
351- [userInfo_ release ];
352- [change_ release ];
353- [super dealloc ];
354- }
355-
356330- (instancetype )copyWithZone : (NSZone *)zone {
357331 return [[[self class ] allocWithZone: zone] initWithKeyPath: keyPath_
358332 ofObject: object_
@@ -448,40 +422,41 @@ @implementation NSObject (GTMDebugKeyValueObserving)
448422 _gtmDebugArrayRemoveObserver:fromObjectsAtIndexes:forKeyPath:);
449423
450424+ (void )load {
451- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc ] init ];
452- NSDictionary *env = [[NSProcessInfo processInfo ] environment ];
453- id debugKeyValue = [env valueForKey: @" GTMDebugKVO" ];
454- BOOL debug = NO ;
455- if ([debugKeyValue isKindOfClass: [NSNumber class ]]) {
456- debug = [debugKeyValue intValue ] != 0 ? YES : NO ;
457- } else if ([debugKeyValue isKindOfClass: [NSString class ]]) {
458- debug = ([debugKeyValue hasPrefix: @" Y" ] || [debugKeyValue hasPrefix: @" T" ] ||
459- [debugKeyValue intValue ]);
460- }
461- Class cls = Nil ;
462- if (debug) {
463- cls = [NSObject class ];
464- SwizzleMethodsInClass (cls,
465- @selector (addObserver:forKeyPath:options:context: ),
466- @selector (_gtmDebugAddObserver:forKeyPath:options:context: ));
467- SwizzleMethodsInClass (cls,
468- @selector (removeObserver:forKeyPath: ),
469- @selector (_gtmDebugRemoveObserver:forKeyPath: ));
470- SwizzleMethodsInClass (cls,
471- @selector (willChangeValueForKey: ),
472- @selector (_gtmDebugWillChangeValueForKey: ));
473- SwizzleMethodsInClass (cls,
474- @selector (didChangeValueForKey: ),
475- @selector (_gtmDebugDidChangeValueForKey: ));
476- cls = [NSArray class ];
477- SwizzleMethodsInClass (cls,
478- @selector (addObserver:toObjectsAtIndexes:forKeyPath:options:context: ),
479- @selector (_gtmDebugArrayAddObserver:toObjectsAtIndexes:forKeyPath:options:context: ));
480- SwizzleMethodsInClass (cls,
481- @selector (removeObserver:fromObjectsAtIndexes:forKeyPath: ),
482- @selector (_gtmDebugArrayRemoveObserver:fromObjectsAtIndexes:forKeyPath: ));
425+ @autoreleasepool {
426+
427+ NSDictionary *env = [[NSProcessInfo processInfo ] environment ];
428+ id debugKeyValue = [env valueForKey: @" GTMDebugKVO" ];
429+ BOOL debug = NO ;
430+ if ([debugKeyValue isKindOfClass: [NSNumber class ]]) {
431+ debug = [debugKeyValue intValue ] != 0 ? YES : NO ;
432+ } else if ([debugKeyValue isKindOfClass: [NSString class ]]) {
433+ debug = ([debugKeyValue hasPrefix: @" Y" ] || [debugKeyValue hasPrefix: @" T" ] ||
434+ [debugKeyValue intValue ]);
435+ }
436+ Class cls = Nil ;
437+ if (debug) {
438+ cls = [NSObject class ];
439+ SwizzleMethodsInClass (cls,
440+ @selector (addObserver:forKeyPath:options:context: ),
441+ @selector (_gtmDebugAddObserver:forKeyPath:options:context: ));
442+ SwizzleMethodsInClass (cls,
443+ @selector (removeObserver:forKeyPath: ),
444+ @selector (_gtmDebugRemoveObserver:forKeyPath: ));
445+ SwizzleMethodsInClass (cls,
446+ @selector (willChangeValueForKey: ),
447+ @selector (_gtmDebugWillChangeValueForKey: ));
448+ SwizzleMethodsInClass (cls,
449+ @selector (didChangeValueForKey: ),
450+ @selector (_gtmDebugDidChangeValueForKey: ));
451+ cls = [NSArray class ];
452+ SwizzleMethodsInClass (cls,
453+ @selector (addObserver:toObjectsAtIndexes:forKeyPath:options:context: ),
454+ @selector (_gtmDebugArrayAddObserver:toObjectsAtIndexes:forKeyPath:options:context: ));
455+ SwizzleMethodsInClass (cls,
456+ @selector (removeObserver:fromObjectsAtIndexes:forKeyPath: ),
457+ @selector (_gtmDebugArrayRemoveObserver:fromObjectsAtIndexes:forKeyPath: ));
458+ }
483459 }
484- [pool drain ];
485460}
486461
487462- (void )_gtmDebugAddObserver : (NSObject *)observer
0 commit comments