aboutsummaryrefslogtreecommitdiff
path: root/Foundation
diff options
context:
space:
mode:
authorGravatar gtm.daemon <gtm.daemon@7dc7ac4e-7543-0410-b95c-c1676fc8e2a3>2009-08-11 18:30:29 +0000
committerGravatar gtm.daemon <gtm.daemon@7dc7ac4e-7543-0410-b95c-c1676fc8e2a3>2009-08-11 18:30:29 +0000
commit1ddb352f1d7621deeb93848dedf034dc5d271a1f (patch)
tree0e3c060f447f687396ac3bb416cf02ae3b671f42 /Foundation
parenta4a6a27c10d9d78034c759678be0ebf95ff3d76c (diff)
[Author: dmaclach]
Fixed up GTMGoogleSearch so that it actually works on the iPhone Device. Fixed up some GTMNSObject+KVO issues on the iPhone Device. Fixed up GTMObjC2Runtime so that it actually compiles on the device. Added debugging capabilities to KVO with GTM. Removed unnecessary GTM_* system version macros from GTMDefines.h R=thomasvl DELTA=185 (153 added, 19 deleted, 13 changed)
Diffstat (limited to 'Foundation')
-rw-r--r--Foundation/GTMGoogleSearch.h4
-rw-r--r--Foundation/GTMGoogleSearch.m11
-rw-r--r--Foundation/GTMGoogleSearchTest.m15
-rw-r--r--Foundation/GTMNSObject+KeyValueObserving.m124
-rw-r--r--Foundation/GTMNSObject+KeyValueObservingTest.m3
-rw-r--r--Foundation/GTMObjC2Runtime.h17
6 files changed, 159 insertions, 15 deletions
diff --git a/Foundation/GTMGoogleSearch.h b/Foundation/GTMGoogleSearch.h
index d18aadf..06b8d51 100644
--- a/Foundation/GTMGoogleSearch.h
+++ b/Foundation/GTMGoogleSearch.h
@@ -32,6 +32,10 @@
#define GTMGoogleSearchBooks @"books"
#define GTMGoogleSearchWeb @"search"
+// iPhone doesn't support distributed notifications, so this controls whether
+// or not we enable them in this class.
+#define GTM_GOOGLE_SEARCH_SUPPORTS_DISTRIBUTED_NOTIFICATIONS GTM_MACOS_SDK
+
// Composes URLs and searches for google properties in the correct language
// and domain.
@interface GTMGoogleSearch : NSObject {
diff --git a/Foundation/GTMGoogleSearch.m b/Foundation/GTMGoogleSearch.m
index 586efd3..56dcc82 100644
--- a/Foundation/GTMGoogleSearch.m
+++ b/Foundation/GTMGoogleSearch.m
@@ -131,6 +131,7 @@ GTMOBJECT_SINGLETON_BOILERPLATE(GTMGoogleSearch, sharedInstance);
- (id)init {
self = [super init];
if (self != nil) {
+#if GTM_GOOGLE_SEARCH_SUPPORTS_DISTRIBUTED_NOTIFICATIONS
// register for the notification
NSDistributedNotificationCenter *distCenter =
[NSDistributedNotificationCenter defaultCenter];
@@ -138,7 +139,7 @@ GTMOBJECT_SINGLETON_BOILERPLATE(GTMGoogleSearch, sharedInstance);
selector:@selector(reloadAllAppCachedValues:)
name:kNotificationName
object:nil];
-
+#endif // GTM_GOOGLE_SEARCH_SUPPORTS_DISTRIBUTED_NOTIFICATIONS
// load the allApps value
[self reloadAllAppCachedValues:nil];
@@ -175,13 +176,17 @@ GTMOBJECT_SINGLETON_BOILERPLATE(GTMGoogleSearch, sharedInstance);
return self;
}
+#if GTM_GOOGLE_SEARCH_SUPPORTS_DISTRIBUTED_NOTIFICATIONS
- (void)finalize {
[[NSDistributedNotificationCenter defaultCenter] removeObject:self];
[super finalize];
}
+#endif // GTM_GOOGLE_SEARCH_SUPPORTS_DISTRIBUTED_NOTIFICATIONS
- (void)dealloc {
+#if GTM_GOOGLE_SEARCH_SUPPORTS_DISTRIBUTED_NOTIFICATIONS
[[NSDistributedNotificationCenter defaultCenter] removeObject:self];
+#endif // GTM_GOOGLE_SEARCH_SUPPORTS_DISTRIBUTED_NOTIFICATIONS
[allAppsCachedDomain_ release];
[allAppsCachedLanguage_ release];
[curAppCachedDomain_ release];
@@ -341,7 +346,7 @@ GTMOBJECT_SINGLETON_BOILERPLATE(GTMGoogleSearch, sharedInstance);
NSNull *nsNull = [NSNull null];
GTM_FOREACH_KEY(key, args) {
NSString *object = [args objectForKey:key];
- if (![object isEqualTo:nsNull]) {
+ if (![object isEqual:nsNull]) {
#if DEBUG
// In debug we check key and object for things that should be escaped.
// Note that percent is not in there because escaped strings will have
@@ -515,6 +520,7 @@ GTMOBJECT_SINGLETON_BOILERPLATE(GTMGoogleSearch, sharedInstance);
allAppsCachedDomain_ = [domain copy];
allAppsCachedLanguage_ = [language copy];
+#if GTM_GOOGLE_SEARCH_SUPPORTS_DISTRIBUTED_NOTIFICATIONS
// NOTE: we'll go ahead and reload when this comes back to ourselves since
// there is a race here if two folks wrote at about the same time.
NSDistributedNotificationCenter *distCenter =
@@ -522,6 +528,7 @@ GTMOBJECT_SINGLETON_BOILERPLATE(GTMGoogleSearch, sharedInstance);
[distCenter postNotificationName:kNotificationName
object:nil
userInfo:nil];
+#endif // GTM_GOOGLE_SEARCH_SUPPORTS_DISTRIBUTED_NOTIFICATIONS
}
@end
diff --git a/Foundation/GTMGoogleSearchTest.m b/Foundation/GTMGoogleSearchTest.m
index 8e737c9..45f7e66 100644
--- a/Foundation/GTMGoogleSearchTest.m
+++ b/Foundation/GTMGoogleSearchTest.m
@@ -166,15 +166,20 @@
STAssertEqualObjects(domain, @"domain", nil);
STAssertEqualObjects(lang, @"lang", nil);
STAssertFalse(areCurrentAppOnly, nil);
+#if GTM_GOOGLE_SEARCH_SUPPORTS_DISTRIBUTED_NOTIFICATIONS
+ // We don't test launching other tasks on the phone since this isn't a valid
+ // case until we can support real multiple tasks on the phone.
// try changing the value directly in the plist file (as if another app had
// done it) and sending our notification.
[[NSTask launchedTaskWithLaunchPath:@"/usr/bin/defaults"
arguments:[NSArray arrayWithObjects:@"write",
@"com.google.GoogleSearchAllApps",
- @"{ \"com.google.PreferredDomain\" = xxx; \"com.google.PreferredLanguage\" = yyy; }",
+ @"{ \"com.google.PreferredDomain\" = xxx;"
+ @"\"com.google.PreferredLanguage\" = yyy; }",
nil]] waitUntilExit];
- // Sleep for a moment to let things flush (seen rarely as a problem on aharper's machine)
+ // Sleep for a moment to let things flush
+ // (seen rarely as a problem on aharper's machine).
sleep(1);
NSDistributedNotificationCenter *distCenter =
[NSDistributedNotificationCenter defaultCenter];
@@ -184,7 +189,8 @@
options:NSNotificationDeliverImmediately];
// Spin the runloop so the notifications fire.
- [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1.0]];
+ NSRunLoop *currentLoop = [NSRunLoop currentRunLoop];
+ [currentLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1.0]];
// did we get what we expected?
[googleSearch preferredDomain:&domain
language:&lang
@@ -192,7 +198,8 @@
STAssertEqualObjects(domain, @"xxx", nil);
STAssertEqualObjects(lang, @"yyy", nil);
STAssertFalse(areCurrentAppOnly, nil);
-
+#endif // GTM_GOOGLE_SEARCH_SUPPORTS_DISTRIBUTED_NOTIFICATIONS
+
// lastly, clean up what we set for all apps to leave the system at the
// default.
[googleSearch clearPreferredDomainAndLanguageForAllApps];
diff --git a/Foundation/GTMNSObject+KeyValueObserving.m b/Foundation/GTMNSObject+KeyValueObserving.m
index dc6883d..e164e03 100644
--- a/Foundation/GTMNSObject+KeyValueObserving.m
+++ b/Foundation/GTMNSObject+KeyValueObserving.m
@@ -27,8 +27,6 @@
// See comment in header.
#import "GTMNSObject+KeyValueObserving.h"
-
-#import <libkern/OSAtomic.h>
#import "GTMDefines.h"
#import "GTMDebugSelectorValidation.h"
#import "GTMObjC2Runtime.h"
@@ -115,6 +113,13 @@ static char* GTMKeyValueObservingHelperContext
return self;
}
+- (NSString *)description {
+ return [NSString stringWithFormat:
+ @"%@ <observer = %@ keypath = %@ target = %@ selector = %@>",
+ [self class], observer_, keyPath_, target_,
+ NSStringFromSelector(selector_)];
+}
+
- (void)dealloc {
[userInfo_ release];
[keyPath_ release];
@@ -327,6 +332,12 @@ static char* GTMKeyValueObservingHelperContext
&& [change_ isEqual:[object change]]);
}
+- (NSString *)description {
+ return [NSString stringWithFormat:
+ @"%@ <object = %@ keypath = %@ userInfo = %@ change = %@>",
+ [self class], object_, keyPath_, userInfo_, change_];
+}
+
- (NSUInteger)hash {
return [keyPath_ hash] + [object_ hash] + [userInfo_ hash] + [change_ hash];
}
@@ -348,3 +359,112 @@ static char* GTMKeyValueObservingHelperContext
}
@end
+
+#ifdef DEBUG
+
+// This category exists to attempt to help debug tricky KVO issues.
+// Set the GTMDebugKVO environment variable to 1 and you will get a whole
+// pile of KVO notifications that may help you track down problems.
+@interface NSObject (GTMDebugKeyValueObserving)
+@end
+
+@implementation NSObject (GTMDebugKeyValueObserving)
++ (void)load {
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ NSDictionary *env = [[NSProcessInfo processInfo] environment];
+ id debugKeyValue = [env valueForKey:@"GTMDebugKVO"];
+ BOOL debug = NO;
+ if ([debugKeyValue isKindOfClass:[NSNumber class]]) {
+ debug = [debugKeyValue intValue] != 0 ? YES : NO;
+ } else if ([debugKeyValue isKindOfClass:[NSString class]]) {
+ debug = ([debugKeyValue hasPrefix:@"Y"] || [debugKeyValue hasPrefix:@"T"] ||
+ [debugKeyValue intValue]);
+ }
+ if (debug) {
+ Class cls = [NSObject class];
+ SEL addSelector
+ = NSSelectorFromString(@"addObserver:forKeyPath:options:context:");
+ SEL removeSelector = NSSelectorFromString(@"removeObserver:forKeyPath:");
+ SEL debugAddSelector
+ = NSSelectorFromString(@"_gtmDebugAddObserver:forKeyPath:options:context:");
+ SEL debugRemoveSelector
+ = NSSelectorFromString(@"_gtmDebugRemoveObserver:forKeyPath:");
+ SEL willChangeValueSelector = NSSelectorFromString(@"willChangeValueForKey:");
+ SEL didChangeValueSelector = NSSelectorFromString(@"didChangeValueForKey:");
+ SEL debugWillChangeValueSelector
+ = NSSelectorFromString(@"_gtmDebugWillChangeValueForKey:");
+ SEL debugDidChangeValueSelector
+ = NSSelectorFromString(@"_gtmDebugDidChangeValueForKey:");
+
+ Method m1 = class_getInstanceMethod(cls, addSelector);
+ Method m2 = class_getInstanceMethod(cls, debugAddSelector);
+ method_exchangeImplementations(m1, m2);
+ m1 = class_getInstanceMethod(cls, removeSelector);
+ m2 = class_getInstanceMethod(cls, debugRemoveSelector);
+ method_exchangeImplementations(m1, m2);
+ m1 = class_getInstanceMethod(cls, willChangeValueSelector);
+ m2 = class_getInstanceMethod(cls, debugWillChangeValueSelector);
+ method_exchangeImplementations(m1, m2);
+ m1 = class_getInstanceMethod(cls, didChangeValueSelector);
+ m2 = class_getInstanceMethod(cls, debugDidChangeValueSelector);
+ method_exchangeImplementations(m1, m2);
+
+ debugAddSelector
+ = NSSelectorFromString(@"_gtmDebugArrayAddObserver:forKeyPath:options:context:");
+ debugRemoveSelector
+ = NSSelectorFromString(@"_gtmDebugArrayRemoveObserver:forKeyPath:");
+
+ cls = [NSArray class];
+ m1 = class_getInstanceMethod(cls, addSelector);
+ m2 = class_getInstanceMethod(cls, debugAddSelector);
+ method_exchangeImplementations(m1, m2);
+ m1 = class_getInstanceMethod(cls, removeSelector);
+ m2 = class_getInstanceMethod(cls, debugRemoveSelector);
+ method_exchangeImplementations(m1, m2);
+ }
+ [pool release];
+}
+
+- (void)_gtmDebugAddObserver:(NSObject *)observer
+ forKeyPath:(NSString *)keyPath
+ options:(NSKeyValueObservingOptions)options
+ context:(void *)context {
+ _GTMDevLog(@"Adding observer %@ to %@ keypath '%@'", observer, self, keyPath);
+ [self _gtmDebugAddObserver:observer forKeyPath:keyPath
+ options:options context:context];
+}
+
+- (void)_gtmDebugArrayAddObserver:(NSObject *)observer
+ forKeyPath:(NSString *)keyPath
+ options:(NSKeyValueObservingOptions)options
+ context:(void *)context {
+ _GTMDevLog(@"Array adding observer %@ to %@ keypath '%@'", observer, self, keyPath);
+ [self _gtmDebugArrayAddObserver:observer forKeyPath:keyPath
+ options:options context:context];
+}
+
+- (void)_gtmDebugRemoveObserver:(NSObject *)observer
+ forKeyPath:(NSString *)keyPath {
+ _GTMDevLog(@"Removing observer %@ from %@ keypath '%@'", observer, self, keyPath);
+ [self _gtmDebugRemoveObserver:observer forKeyPath:keyPath];
+}
+
+- (void)_gtmDebugArrayRemoveObserver:(NSObject *)observer
+ forKeyPath:(NSString *)keyPath {
+ _GTMDevLog(@"Array removing observer %@ from %@ keypath '%@'", observer, self, keyPath);
+ [self _gtmDebugArrayRemoveObserver:observer forKeyPath:keyPath];
+}
+
+- (void)_gtmDebugWillChangeValueForKey:(NSString*)key {
+ _GTMDevLog(@"Will change '%@' of %@", key, self);
+ [self _gtmDebugWillChangeValueForKey:key];
+}
+
+- (void)_gtmDebugDidChangeValueForKey:(NSString*)key {
+ _GTMDevLog(@"Did change '%@' of %@", key, self);
+ [self _gtmDebugDidChangeValueForKey:key];
+}
+
+#endif // DEBUG
+
+@end
diff --git a/Foundation/GTMNSObject+KeyValueObservingTest.m b/Foundation/GTMNSObject+KeyValueObservingTest.m
index b97f7ff..ec35bc3 100644
--- a/Foundation/GTMNSObject+KeyValueObservingTest.m
+++ b/Foundation/GTMNSObject+KeyValueObservingTest.m
@@ -87,6 +87,9 @@
selector:@selector(observeValueChange:)
userInfo:@"userInfo"
options:NSKeyValueObservingOptionNew];
+ [dict_ gtm_removeObserver:self
+ forKeyPath:@"key"
+ selector:@selector(observeValueChange:)];
}
- (void)observeValueChange:(GTMKeyValueChangeNotification *)notification {
diff --git a/Foundation/GTMObjC2Runtime.h b/Foundation/GTMObjC2Runtime.h
index 2c25841..4f569a5 100644
--- a/Foundation/GTMObjC2Runtime.h
+++ b/Foundation/GTMObjC2Runtime.h
@@ -75,7 +75,7 @@ OBJC_EXPORT struct objc_method_description protocol_getMethodDescription(Protoco
// barrier versions.
GTM_INLINE bool OSAtomicCompareAndSwapPtrBarrier(void *predicate,
void *replacement,
- volatile void *theValue) {
+ void * volatile *theValue) {
#if defined(__LP64__) && __LP64__
return OSAtomicCompareAndSwap64Barrier((int64_t)predicate,
(int64_t)replacement,
@@ -86,21 +86,24 @@ GTM_INLINE bool OSAtomicCompareAndSwapPtrBarrier(void *predicate,
(int32_t *)theValue);
#endif // defined(__LP64__) && __LP64__
}
-
+
+#endif // MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5
+#endif // MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
+
+#if (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5) || (GTM_IPHONE_DEVICE)
+
GTM_INLINE BOOL objc_atomicCompareAndSwapGlobalBarrier(id predicate,
id replacement,
volatile id *objectLocation) {
return OSAtomicCompareAndSwapPtrBarrier(predicate,
replacement,
- objectLocation);
+ (void * volatile *)objectLocation);
}
GTM_INLINE BOOL objc_atomicCompareAndSwapInstanceVariableBarrier(id predicate,
id replacement,
volatile id *objectLocation) {
return OSAtomicCompareAndSwapPtrBarrier(predicate,
replacement,
- objectLocation);
+ (void * volatile *)objectLocation);
}
-#endif
-
-#endif // OBJC2_UNAVAILABLE
+#endif // (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5) || (GTM_IPHONE_DEVICE)