Skip to content

Commit 2471dde

Browse files
committed
Move GTMNSObject+KeyValueObserving over to ARC
1 parent 75a7581 commit 2471dde

5 files changed

Lines changed: 75 additions & 81 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-
non_arc_srcs = [
35+
srcs = [
3636
"GTMNSObject+KeyValueObserving.m",
3737
],
3838
sdk_frameworks = [

Foundation/GTMNSObject+KeyValueObserving.m

Lines changed: 52 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,7 @@
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(&center, &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

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-
GTM_WEAK NSString *expectedValue_;
36+
__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 */; };
47+
8B6C15940F356E6400E51E5D /* GTMNSObject+KeyValueObserving.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B6C15920F356E6400E51E5D /* GTMNSObject+KeyValueObserving.m */; settings = {COMPILER_FLAGS = "-fobjc-arc"; }; };
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: 20 additions & 1 deletion
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 */; };
24+
8B82CF0D1D9C1C3B007182AA /* GTMNSObject+KeyValueObserving.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B6C18720F3769D200E51E5D /* GTMNSObject+KeyValueObserving.m */; settings = {COMPILER_FLAGS = "-fobjc-arc"; }; };
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,6 +64,16 @@
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+
6777
/* Begin PBXCopyFilesBuildPhase section */
6878
8B82CEF41D9C17DE007182AA /* CopyFiles */ = {
6979
isa = PBXCopyFilesBuildPhase;
@@ -462,6 +472,7 @@
462472
buildRules = (
463473
);
464474
dependencies = (
475+
8BFA304A2E562C740037F469 /* PBXTargetDependency */,
465476
);
466477
name = GTMTests;
467478
productName = GTMTests;
@@ -593,6 +604,14 @@
593604
};
594605
/* End PBXSourcesBuildPhase section */
595606

607+
/* Begin PBXTargetDependency section */
608+
8BFA304A2E562C740037F469 /* PBXTargetDependency */ = {
609+
isa = PBXTargetDependency;
610+
target = 8B82CEF51D9C17DE007182AA /* GTM */;
611+
targetProxy = 8BFA30492E562C740037F469 /* PBXContainerItemProxy */;
612+
};
613+
/* End PBXTargetDependency section */
614+
596615
/* Begin XCBuildConfiguration section */
597616
8B82CEFD1D9C17DE007182AA /* Debug */ = {
598617
isa = XCBuildConfiguration;

0 commit comments

Comments
 (0)