Skip to content

Commit 1e9fa5d

Browse files
committed
Revert "Move GTMNSObject+KeyValueObserving over to ARC (#548)"
This reverts commit 27f71f8.
1 parent 31ef581 commit 1e9fa5d

6 files changed

Lines changed: 81 additions & 77 deletions

File tree

Foundation/BUILD

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ objc_library(
3232
"GTMNSObject+KeyValueObserving.h",
3333
],
3434
copts = ["-IDebugUtils"],
35-
srcs = [
35+
non_arc_srcs = [
3636
"GTMNSObject+KeyValueObserving.m",
3737
],
3838
sdk_frameworks = [

Foundation/GTMNSObject+KeyValueObserving.m

Lines changed: 77 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@
2727
// See comment in header.
2828
#import "GTMNSObject+KeyValueObserving.h"
2929

30+
#import <libkern/OSAtomic.h>
3031
#include <objc/runtime.h>
32+
#import <stdatomic.h>
3133

3234
#import "GTMDefines.h"
3335
#import "GTMDebugSelectorValidation.h"
@@ -62,10 +64,11 @@ - (id)dictionaryKeyForObserver:(id)observer
6264
@end
6365

6466
@interface GTMKeyValueObservingHelper : NSObject {
65-
__weak id observer_;
67+
@private
68+
GTM_WEAK id observer_;
6669
SEL selector_;
6770
id userInfo_;
68-
__weak id target_;
71+
GTM_WEAK id target_;
6972
NSString* keyPath_;
7073
}
7174

@@ -103,10 +106,10 @@ - (instancetype)initWithObserver:(id)observer
103106
if((self = [super init])) {
104107
observer_ = observer;
105108
selector_ = selector;
106-
userInfo_ = userInfo;
109+
userInfo_ = [userInfo retain];
107110

108111
target_ = target;
109-
keyPath_ = keyPath;
112+
keyPath_ = [keyPath retain];
110113

111114
[target addObserver:self
112115
forKeyPath:keyPath
@@ -128,6 +131,9 @@ - (void)dealloc {
128131
_GTMDevLog(@"Didn't deregister %@", self);
129132
[self deregister];
130133
}
134+
[userInfo_ release];
135+
[keyPath_ release];
136+
[super dealloc];
131137
}
132138

133139
- (void)observeValueForKeyPath:(NSString *)keyPath
@@ -140,11 +146,8 @@ - (void)observeValueForKeyPath:(NSString *)keyPath
140146
ofObject:object
141147
userInfo:userInfo_
142148
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.
146149
[observer_ performSelector:selector_ withObject:notification];
147-
#pragma clang diagnostic pop
150+
[notification release];
148151
} else {
149152
// COV_NF_START
150153
// There's no way this should ever be called.
@@ -160,20 +163,26 @@ - (void)observeValueForKeyPath:(NSString *)keyPath
160163
- (void)deregister {
161164
[target_ removeObserver:self forKeyPath:keyPath_];
162165
target_ = nil;
163-
observer_ = nil;
164166
}
165167

166168
@end
167169

168170
@implementation GTMKeyValueObservingCenter
169171

170172
+ (instancetype)defaultCenter {
171-
static dispatch_once_t onceToken;
172-
static GTMKeyValueObservingCenter *center;
173-
dispatch_once(&onceToken, ^{
174-
center = [[self alloc] init];
175-
});
176-
return center;
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(&center, &expected, newCenter)) {
182+
[newCenter release]; // COV_NF_LINE no guarantee we'll hit this line
183+
}
184+
}
185+
return center;
177186
}
178187

179188
- (instancetype)init {
@@ -183,6 +192,14 @@ - (instancetype)init {
183192
return self;
184193
}
185194

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+
186203
- (id)dictionaryKeyForObserver:(id)observer
187204
ofObject:(id)target
188205
forKeyPath:(NSString *)keyPath
@@ -223,6 +240,7 @@ - (void)addObserver:(id)observer
223240
}
224241
[observerHelpers_ setObject:helper forKey:key];
225242
}
243+
[helper release];
226244
}
227245

228246
- (void)removeObserver:(id)observer
@@ -320,13 +338,21 @@ - (instancetype)initWithKeyPath:(NSString *)keyPath
320338
change:(NSDictionary *)change {
321339
if ((self = [super init])) {
322340
keyPath_ = [keyPath copy];
323-
object_ = object;
324-
userInfo_ = userInfo;
325-
change_ = change;
341+
object_ = [object retain];
342+
userInfo_ = [userInfo retain];
343+
change_ = [change retain];
326344
}
327345
return self;
328346
}
329347

348+
- (void)dealloc {
349+
[keyPath_ release];
350+
[object_ release];
351+
[userInfo_ release];
352+
[change_ release];
353+
[super dealloc];
354+
}
355+
330356
- (instancetype)copyWithZone:(NSZone *)zone {
331357
return [[[self class] allocWithZone:zone] initWithKeyPath:keyPath_
332358
ofObject:object_
@@ -422,41 +448,40 @@ @implementation NSObject (GTMDebugKeyValueObserving)
422448
_gtmDebugArrayRemoveObserver:fromObjectsAtIndexes:forKeyPath:);
423449

424450
+ (void)load {
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-
}
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:));
459483
}
484+
[pool drain];
460485
}
461486

462487
- (void)_gtmDebugAddObserver:(NSObject *)observer

Foundation/GTMNSObject+KeyValueObservingTest.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
@interface GTMNSObject_KeyValueObservingTest : GTMTestCase {
3434
int32_t count_;
3535
NSMutableDictionary *dict_;
36-
NSString *expectedValue_;
36+
GTM_WEAK NSString *expectedValue_;
3737
}
3838

3939
- (void)observeValueChange:(GTMKeyValueChangeNotification *)notification;

GTM.xcodeproj/project.pbxproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
8B5769AB21CD7ACF00D924D3 /* GTMTimeUtilsTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B5769A921CD798000D924D3 /* GTMTimeUtilsTest.m */; };
4545
8B61FDC00E4CDB8000FF9C21 /* GTMStackTrace.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B61FDBF0E4CDB8000FF9C21 /* GTMStackTrace.m */; };
4646
8B6C15930F356E6400E51E5D /* GTMNSObject+KeyValueObserving.h in Headers */ = {isa = PBXBuildFile; fileRef = 8B6C15910F356E6400E51E5D /* GTMNSObject+KeyValueObserving.h */; settings = {ATTRIBUTES = (Public, ); }; };
47-
8B6C15940F356E6400E51E5D /* GTMNSObject+KeyValueObserving.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B6C15920F356E6400E51E5D /* GTMNSObject+KeyValueObserving.m */; settings = {COMPILER_FLAGS = "-fobjc-arc"; }; };
47+
8B6C15940F356E6400E51E5D /* GTMNSObject+KeyValueObserving.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B6C15920F356E6400E51E5D /* GTMNSObject+KeyValueObserving.m */; };
4848
8B6F4B630E8856CA00425D9F /* GTMDebugThreadValidation.h in Headers */ = {isa = PBXBuildFile; fileRef = 8B6F4B610E8856CA00425D9F /* GTMDebugThreadValidation.h */; settings = {ATTRIBUTES = (Public, ); }; };
4949
8B6F4B640E8856CA00425D9F /* GTMDebugThreadValidation.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B6F4B620E8856CA00425D9F /* GTMDebugThreadValidation.m */; };
5050
8B7DCBA50DFF0EFF0017E983 /* GoogleToolboxForMac.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F42E086D0D199A5B00D5DDE0 /* GoogleToolboxForMac.framework */; };

GTMiPhone.xcodeproj/project.pbxproj

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
8B82CF081D9C1C3B007182AA /* GTMNSData+zlib.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BC0477F0DAE928A00C2D1CA /* GTMNSData+zlib.m */; };
2222
8B82CF0A1D9C1C3B007182AA /* GTMNSFileManager+Path.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BC047850DAE928A00C2D1CA /* GTMNSFileManager+Path.m */; };
2323
8B82CF0B1D9C1C3B007182AA /* GTMNSFileHandle+UniqueName.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B2908B011F8E7070064F50F /* GTMNSFileHandle+UniqueName.m */; };
24-
8B82CF0D1D9C1C3B007182AA /* GTMNSObject+KeyValueObserving.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B6C18720F3769D200E51E5D /* GTMNSObject+KeyValueObserving.m */; settings = {COMPILER_FLAGS = "-fobjc-arc"; }; };
24+
8B82CF0D1D9C1C3B007182AA /* GTMNSObject+KeyValueObserving.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B6C18720F3769D200E51E5D /* GTMNSObject+KeyValueObserving.m */; };
2525
8B82CF0F1D9C1C3B007182AA /* GTMNSString+HTML.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BC047880DAE928A00C2D1CA /* GTMNSString+HTML.m */; };
2626
8B82CF111D9C1C3B007182AA /* GTMNSString+XML.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BC0478B0DAE928A00C2D1CA /* GTMNSString+XML.m */; };
2727
8B82CF121D9C1C3B007182AA /* GTMNSThread+Blocks.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B6FF392151A664600B0642B /* GTMNSThread+Blocks.m */; };
@@ -64,16 +64,6 @@
6464
F4A1EEA52B62D38F008B2FC1 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = F4A1EEA12B62D338008B2FC1 /* PrivacyInfo.xcprivacy */; };
6565
/* End PBXBuildFile section */
6666

67-
/* Begin PBXContainerItemProxy section */
68-
8BFA30492E562C740037F469 /* PBXContainerItemProxy */ = {
69-
isa = PBXContainerItemProxy;
70-
containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */;
71-
proxyType = 1;
72-
remoteGlobalIDString = 8B82CEF51D9C17DE007182AA;
73-
remoteInfo = GTM;
74-
};
75-
/* End PBXContainerItemProxy section */
76-
7767
/* Begin PBXCopyFilesBuildPhase section */
7868
8B82CEF41D9C17DE007182AA /* CopyFiles */ = {
7969
isa = PBXCopyFilesBuildPhase;
@@ -472,7 +462,6 @@
472462
buildRules = (
473463
);
474464
dependencies = (
475-
8BFA304A2E562C740037F469 /* PBXTargetDependency */,
476465
);
477466
name = GTMTests;
478467
productName = GTMTests;
@@ -604,14 +593,6 @@
604593
};
605594
/* End PBXSourcesBuildPhase section */
606595

607-
/* Begin PBXTargetDependency section */
608-
8BFA304A2E562C740037F469 /* PBXTargetDependency */ = {
609-
isa = PBXTargetDependency;
610-
target = 8B82CEF51D9C17DE007182AA /* GTM */;
611-
targetProxy = 8BFA30492E562C740037F469 /* PBXContainerItemProxy */;
612-
};
613-
/* End PBXTargetDependency section */
614-
615596
/* Begin XCBuildConfiguration section */
616597
8B82CEFD1D9C17DE007182AA /* Debug */ = {
617598
isa = XCBuildConfiguration;

GoogleToolboxForMac.podspec

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,6 @@ Pod::Spec.new do |s|
6969
s.subspec 'KVO' do |sp|
7070
sp.source_files =
7171
'Foundation/GTMNSObject+KeyValueObserving.{h,m}'
72-
sp.requires_arc =
73-
'Foundation/GTMNSObject+KeyValueObserving.{h,m}'
7472
sp.dependency 'GoogleToolboxForMac/Core', "#{s.version}"
7573
sp.dependency 'GoogleToolboxForMac/DebugUtils', "#{s.version}"
7674
end

0 commit comments

Comments
 (0)