Avoid calling depreceted methods just because KVO has overridden them.

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@26170 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
rfm 2008-03-02 08:23:51 +00:00
parent d429949533
commit 04d03bff35
3 changed files with 102 additions and 50 deletions

View file

@ -1,3 +1,9 @@
2008-03-02 Richard Frith-Macdonald <rfm@gnu.org>
* Source/NSKeyValueCoding.m: Avoid calling deprecated methods as a
result of KVO overriding them.
* Source/NSKeyValueObserving.m: Minor tidyups
2008-02-25 Richard Frith-Macdonald <rfm@gnu.org> 2008-02-25 Richard Frith-Macdonald <rfm@gnu.org>
* Headers/Foundation/NSObject.h: Moved some headers to NSObjCRuntime.h * Headers/Foundation/NSObject.h: Moved some headers to NSObjCRuntime.h

View file

@ -55,6 +55,31 @@ NSString* const NSUndefinedKeyException = @"NSUnknownKeyException";
/* this should move into autoconf once it's accepted */ /* this should move into autoconf once it's accepted */
#define WANT_DEPRECATED_KVC_COMPAT 1 #define WANT_DEPRECATED_KVC_COMPAT 1
#ifdef WANT_DEPRECATED_KVC_COMPAT
static IMP takePath = 0;
static IMP takeValue = 0;
static IMP takePathKVO = 0;
static IMP takeValueKVO = 0;
static inline void setupCompat()
{
if (takePath == 0)
{
Class c = NSClassFromString(@"GSKVOBase");
takePathKVO = [c instanceMethodForSelector:
@selector(takeValue:forKeyPath:)];
takePath = [NSObject instanceMethodForSelector:
@selector(takeValue:forKeyPath:)];
takeValueKVO = [c instanceMethodForSelector:
@selector(takeValue:forKey:)];
takeValue = [NSObject instanceMethodForSelector:
@selector(takeValue:forKey:)];
}
}
#endif
static void static void
SetValueForKey(NSObject *self, id anObject, const char *key, unsigned size) SetValueForKey(NSObject *self, id anObject, const char *key, unsigned size)
@ -340,16 +365,12 @@ static id ValueForKey(NSObject *self, const char *key, unsigned size)
unsigned size = [aKey length] * 8; unsigned size = [aKey length] * 8;
char key[size+1]; char key[size+1];
#ifdef WANT_DEPRECATED_KVC_COMPAT #ifdef WANT_DEPRECATED_KVC_COMPAT
static IMP o = 0; IMP o = [self methodForSelector: @selector(takeValue:forKey:)];
/* Backward compatibility hack */ setupCompat();
if (o == 0) if (o != takeValue && o != takeValueKVO)
{ {
o = [NSObject instanceMethodForSelector: @selector(takeValue:forKey:)]; (*o)(self, @selector(takeValue:forKey:), aKey);
}
if ([self methodForSelector: @selector(takeValue:forKey:)] != o)
{
[self takeValue: anObject forKey: aKey];
return; return;
} }
#endif #endif
@ -370,17 +391,12 @@ static id ValueForKey(NSObject *self, const char *key, unsigned size)
unsigned end = 0; unsigned end = 0;
id obj = self; id obj = self;
#ifdef WANT_DEPRECATED_KVC_COMPAT #ifdef WANT_DEPRECATED_KVC_COMPAT
static IMP o = 0; IMP o = [self methodForSelector: @selector(takeValue:forKeyPath:)];
/* Backward compatibility hack */ setupCompat();
if (o == 0) if (o != takePath && o != takePathKVO)
{ {
o = [NSObject instanceMethodForSelector: (*o)(self, @selector(takeValue:forKeyPath:), anObject, aKey);
@selector(takeValue:forKeyPath:)];
}
if ([self methodForSelector: @selector(takeValue:forKeyPath:)] != o)
{
[self takeValue: anObject forKeyPath: aKey];
return; return;
} }
#endif #endif

View file

@ -143,12 +143,12 @@ static inline void setup()
NSMapTable *paths; NSMapTable *paths;
NSMutableDictionary *changes; NSMutableDictionary *changes;
} }
- (void) notifyForKey: (NSString *)aKey ofChange: (NSDictionary *)change; - (NSMutableDictionary *) changeForKey: (NSString *)key;
- (void) setChange: (NSDictionary *)info forKey: (NSString *)key; - (void*) contextForObserver: (NSObject*)anObserver ofKeyPath: (NSString*)aPath;
- (NSDictionary *) changeForKey: (NSString *)key;
- (id) initWithInstance: (NSObject*)i; - (id) initWithInstance: (NSObject*)i;
- (BOOL) isUnobserved; - (BOOL) isUnobserved;
- (void*) contextForObserver: (NSObject*)anObserver ofKeyPath: (NSString*)aPath; - (void) notifyForKey: (NSString *)aKey ofChange: (NSDictionary *)change;
- (void) setChange: (NSMutableDictionary *)info forKey: (NSString *)key;
@end @end
@ -369,6 +369,22 @@ replacementForClass(Class c)
NSString *superName; NSString *superName;
NSString *name; NSString *name;
if ([aClass instanceMethodForSelector: @selector(takeValue:forKey:)]
!= [NSObject instanceMethodForSelector: @selector(takeValue:forKey:)])
{
NSLog(@"WARNING The class '%@' (or one of its superclasses) overrides"
@" the deprecated takeValue:forKey: method. Using KVO to observe"
@" this class may interfere with this method. Please change the"
@" class to override -setValue:forKey: instead.");
}
if ([aClass instanceMethodForSelector: @selector(takeValue:forKeyPath:)]
!= [NSObject instanceMethodForSelector: @selector(takeValue:forKeyPath:)])
{
NSLog(@"WARNING The class '%@' (or one of its superclasses) overrides"
@" the deprecated takeValue:forKeyPath: method. Using KVO to observe"
@" this class may interfere with this method. Please change the"
@" class to override -setValue:forKeyPath: instead.");
}
original = aClass; original = aClass;
/* /*
@ -797,6 +813,7 @@ replacementForClass(Class c)
{ {
if (paths != 0) NSFreeMapTable(paths); if (paths != 0) NSFreeMapTable(paths);
RELEASE(iLock); RELEASE(iLock);
RELEASE(changes);
[super dealloc]; [super dealloc];
} }
@ -846,13 +863,12 @@ replacementForClass(Class c)
return self; return self;
} }
- (void) setChange: (NSDictionary *)info forKey: (NSString *)key - (void) setChange: (NSMutableDictionary *)info forKey: (NSString *)key
{ {
[changes setValue: info forKey: key]; [changes setValue: info forKey: key];
} }
- (NSDictionary *) changeForKey: (NSString *)key - (NSMutableDictionary *) changeForKey: (NSString *)key
{ {
return [changes valueForKey: key]; return [changes valueForKey: key];
} }
@ -876,7 +892,7 @@ replacementForClass(Class c)
- (void) removeObserver: (NSObject*)anObserver forKeyPath: (NSString*)aPath - (void) removeObserver: (NSObject*)anObserver forKeyPath: (NSString*)aPath
{ {
NSMapTable *observers; NSMapTable *observers;
NSMapTable * observer; NSMapTable *observer;
[iLock lock]; [iLock lock];
observers = (NSMapTable*)NSMapGet(paths, (void*)aPath); observers = (NSMapTable*)NSMapGet(paths, (void*)aPath);
@ -899,8 +915,8 @@ replacementForClass(Class c)
- (void*) contextForObserver: (NSObject*)anObserver ofKeyPath: (NSString*)aPath - (void*) contextForObserver: (NSObject*)anObserver ofKeyPath: (NSString*)aPath
{ {
NSMapTable *observers; NSMapTable *observers;
NSMapTable * observer; NSMapTable *observer;
void * context = 0; void *context = 0;
[iLock lock]; [iLock lock];
observers = (NSMapTable*)NSMapGet(paths, (void*)aPath); observers = (NSMapTable*)NSMapGet(paths, (void*)aPath);
@ -921,9 +937,9 @@ replacementForClass(Class c)
@implementation NSKeyValueObservationForwarder @implementation NSKeyValueObservationForwarder
+ (id) forwarderWithKeyPath: (NSString *)keyPath + (id) forwarderWithKeyPath: (NSString *)keyPath
ofObject: (id)object ofObject: (id)object
withTarget: (id)aTarget withTarget: (id)aTarget
context: (void *)context context: (void *)context
{ {
return [[self alloc] initWithKeyPath: keyPath return [[self alloc] initWithKeyPath: keyPath
ofObject: object ofObject: object
@ -1056,7 +1072,8 @@ replacementForClass(Class c)
{ {
id oldValue; id oldValue;
oldValue = [observedObjectForForwarding valueForKey: keyForForwarding]; oldValue
= [observedObjectForForwarding valueForKey: keyForForwarding];
[observedObjectForForwarding removeObserver: self forKeyPath: [observedObjectForForwarding removeObserver: self forKeyPath:
keyForForwarding]; keyForForwarding];
if (oldValue) if (oldValue)
@ -1076,7 +1093,8 @@ replacementForClass(Class c)
| NSKeyValueObservingOptionOld | NSKeyValueObservingOptionOld
context: target]; context: target];
//prepare change notification //prepare change notification
newValue = [observedObjectForForwarding valueForKey: keyForForwarding]; newValue
= [observedObjectForForwarding valueForKey: keyForForwarding];
if (newValue) if (newValue)
{ {
[change setObject: newValue forKey: NSKeyValueChangeNewKey]; [change setObject: newValue forKey: NSKeyValueChangeNewKey];
@ -1310,11 +1328,6 @@ replacementForClass(Class c)
} }
} }
/* FIXME
* It may be beneficial (performance-wise) to only calculate the old and new
* values in the willChange... and didChange... methods if explicitly needed
* by an observer.
*/
- (void) willChangeValueForKey: (NSString*)aKey - (void) willChangeValueForKey: (NSString*)aKey
{ {
GSKVOInfo *info; GSKVOInfo *info;
@ -1325,13 +1338,32 @@ replacementForClass(Class c)
id old; id old;
NSMutableDictionary *change; NSMutableDictionary *change;
change = [NSMutableDictionary dictionary]; change = [info changeForKey: aKey];
old = [self valueForKey: aKey]; if (change == nil)
if (old != nil) {
change = [[NSMutableDictionary alloc] initWithCapacity: 1];
[info setChange: change forKey: aKey];
RELEASE(change);
}
old = [change objectForKey: NSKeyValueChangeNewKey];
if (old == nil)
{
old = [self valueForKey: aKey];
if (old == nil)
{
[change removeObjectForKey: NSKeyValueChangeOldKey];
}
else
{
[change setObject: old forKey: NSKeyValueChangeOldKey];
}
}
else
{ {
[change setObject: old forKey: NSKeyValueChangeOldKey]; [change setObject: old forKey: NSKeyValueChangeOldKey];
} }
[info setChange: change forKey: aKey]; [change removeObjectForKey: NSKeyValueChangeNewKey];
[change removeObjectForKey: NSKeyValueChangeKindKey];
} }
[self willChangeValueForDependentsOfKey: aKey]; [self willChangeValueForDependentsOfKey: aKey];
} }
@ -1350,9 +1382,7 @@ replacementForClass(Class c)
forKey: NSKeyValueChangeNewKey]; forKey: NSKeyValueChangeNewKey];
[change setValue: [NSNumber numberWithInt: NSKeyValueChangeSetting] [change setValue: [NSNumber numberWithInt: NSKeyValueChangeSetting]
forKey: NSKeyValueChangeKindKey]; forKey: NSKeyValueChangeKindKey];
[info notifyForKey: aKey ofChange: change]; [info notifyForKey: aKey ofChange: change];
[info setChange: nil forKey: aKey];
} }
[self didChangeValueForDependentsOfKey: aKey]; [self didChangeValueForDependentsOfKey: aKey];
} }
@ -1384,7 +1414,6 @@ replacementForClass(Class c)
} }
[info notifyForKey: aKey ofChange: change]; [info notifyForKey: aKey ofChange: change];
[info setChange:nil forKey: aKey];
} }
[self didChangeValueForDependentsOfKey: aKey]; [self didChangeValueForDependentsOfKey: aKey];
} }
@ -1397,10 +1426,10 @@ replacementForClass(Class c)
info = [self observationInfo]; info = [self observationInfo];
{ {
NSDictionary *change; NSMutableDictionary *change;
NSMutableArray *array; NSMutableArray *array;
change = [NSMutableDictionary dictionary]; change = [[NSMutableDictionary alloc] initWithCapacity: 1];
array = [self valueForKey: aKey]; array = [self valueForKey: aKey];
if (changeKind == NSKeyValueChangeRemoval if (changeKind == NSKeyValueChangeRemoval
@ -1411,6 +1440,7 @@ replacementForClass(Class c)
} }
[info setChange: change forKey: aKey]; [info setChange: change forKey: aKey];
RELEASE(change);
} }
[self willChangeValueForDependentsOfKey: aKey]; [self willChangeValueForDependentsOfKey: aKey];
} }
@ -1424,14 +1454,15 @@ replacementForClass(Class c)
info = [self observationInfo]; info = [self observationInfo];
if (info != nil) if (info != nil)
{ {
NSDictionary *change; NSMutableDictionary *change;
NSMutableSet *set; NSMutableSet *set;
change = [NSMutableDictionary dictionary]; change = [[NSMutableDictionary alloc] initWithCapacity: 1];
set = [self valueForKey: aKey]; set = [self valueForKey: aKey];
[change setValue: [set mutableCopy] forKey: @"oldSet"]; [change setValue: [set mutableCopy] forKey: @"oldSet"];
[info setChange: change forKey: aKey]; [info setChange: change forKey: aKey];
RELEASE(change);
} }
[self willChangeValueForDependentsOfKey: aKey]; [self willChangeValueForDependentsOfKey: aKey];
} }
@ -1485,7 +1516,6 @@ replacementForClass(Class c)
[change setValue: new forKey: NSKeyValueChangeNewKey]; [change setValue: new forKey: NSKeyValueChangeNewKey];
} }
[info notifyForKey: aKey ofChange: change]; [info notifyForKey: aKey ofChange: change];
[info setChange:nil forKey: aKey];
} }
[self didChangeValueForDependentsOfKey: aKey]; [self didChangeValueForDependentsOfKey: aKey];
} }