diff --git a/Headers/Foundation/NSKeyValueObserving.h b/Headers/Foundation/NSKeyValueObserving.h index e3568f106..a6bb14a58 100644 --- a/Headers/Foundation/NSKeyValueObserving.h +++ b/Headers/Foundation/NSKeyValueObserving.h @@ -138,6 +138,11 @@ GS_EXPORT NSString *const NSKeyValueChangeNotificationIsPriorKey; - (void) removeObserver: (NSObject*)anObserver forKeyPath: (NSString*)aPath; +#if OS_API_VERSION(MAC_OS_X_VERSION_10_7,GS_API_LATEST) +- (void) removeObserver: (NSObject*)anObserver + forKeyPath: (NSString*)aPath + context: (void *)context; +#endif @end @interface NSArray (NSKeyValueObserverRegistration) diff --git a/Source/NSKeyValueObserving.m b/Source/NSKeyValueObserving.m index 7cf27a3db..a375d51ec 100644 --- a/Source/NSKeyValueObserving.m +++ b/Source/NSKeyValueObserving.m @@ -1288,6 +1288,43 @@ cifframe_callback(ffi_cif *cif, void *retp, void **args, void *user) [iLock unlock]; return context; } + +- (void) removeObserver: (NSObject*)anObserver + forKeyPath: (NSString*)aPath + context: (void*)context +{ + GSKVOPathInfo *pathInfo; + + [iLock lock]; + pathInfo = (GSKVOPathInfo*)NSMapGet(paths, (void*)aPath); + if (pathInfo != nil) + { + unsigned count = [pathInfo->observations count]; + + pathInfo->allOptions = 0; + while (count-- > 0) + { + GSKVOObservation *o; + + o = [pathInfo->observations objectAtIndex: count]; + if ((o->observer == anObserver || o->observer == nil) && + (o->context == context)) + { + [pathInfo->observations removeObjectAtIndex: count]; + if ([pathInfo->observations count] == 0) + { + NSMapRemove(paths, (void*)aPath); + } + } + else + { + pathInfo->allOptions |= o->options; + } + } + } + [iLock unlock]; +} + @end @implementation NSKeyValueObservationForwarder @@ -1561,6 +1598,32 @@ cifframe_callback(ffi_cif *cif, void *retp, void **args, void *user) [forwarder finalize]; } +- (void) removeObserver: (NSObject*)anObserver + forKeyPath: (NSString*)aPath + context: (void *)context +{ + GSKVOInfo *info; + + setup(); + [kvoLock lock]; + /* + * Get the observation information and remove this observation. + */ + info = (GSKVOInfo*)[self observationInfo]; + [info removeObserver: anObserver forKeyPath: aPath context: context]; + if ([info isUnobserved] == YES) + { + /* + * The instance is no longer being observed ... so we can + * turn off key-value-observing for it. + */ + object_setClass(self, [self class]); + IF_NO_GC(AUTORELEASE(info);) + [self setObservationInfo: nil]; + } + [kvoLock unlock]; +} + @end /**