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>
* 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 */
#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
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;
char key[size+1];
#ifdef WANT_DEPRECATED_KVC_COMPAT
static IMP o = 0;
IMP o = [self methodForSelector: @selector(takeValue:forKey:)];
/* Backward compatibility hack */
if (o == 0)
setupCompat();
if (o != takeValue && o != takeValueKVO)
{
o = [NSObject instanceMethodForSelector: @selector(takeValue:forKey:)];
}
if ([self methodForSelector: @selector(takeValue:forKey:)] != o)
{
[self takeValue: anObject forKey: aKey];
(*o)(self, @selector(takeValue:forKey:), aKey);
return;
}
#endif
@ -370,17 +391,12 @@ static id ValueForKey(NSObject *self, const char *key, unsigned size)
unsigned end = 0;
id obj = self;
#ifdef WANT_DEPRECATED_KVC_COMPAT
static IMP o = 0;
IMP o = [self methodForSelector: @selector(takeValue:forKeyPath:)];
/* Backward compatibility hack */
if (o == 0)
setupCompat();
if (o != takePath && o != takePathKVO)
{
o = [NSObject instanceMethodForSelector:
@selector(takeValue:forKeyPath:)];
}
if ([self methodForSelector: @selector(takeValue:forKeyPath:)] != o)
{
[self takeValue: anObject forKeyPath: aKey];
(*o)(self, @selector(takeValue:forKeyPath:), anObject, aKey);
return;
}
#endif

View file

@ -143,12 +143,12 @@ static inline void setup()
NSMapTable *paths;
NSMutableDictionary *changes;
}
- (void) notifyForKey: (NSString *)aKey ofChange: (NSDictionary *)change;
- (void) setChange: (NSDictionary *)info forKey: (NSString *)key;
- (NSDictionary *) changeForKey: (NSString *)key;
- (NSMutableDictionary *) changeForKey: (NSString *)key;
- (void*) contextForObserver: (NSObject*)anObserver ofKeyPath: (NSString*)aPath;
- (id) initWithInstance: (NSObject*)i;
- (BOOL) isUnobserved;
- (void*) contextForObserver: (NSObject*)anObserver ofKeyPath: (NSString*)aPath;
- (void) notifyForKey: (NSString *)aKey ofChange: (NSDictionary *)change;
- (void) setChange: (NSMutableDictionary *)info forKey: (NSString *)key;
@end
@ -369,6 +369,22 @@ replacementForClass(Class c)
NSString *superName;
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;
/*
@ -797,6 +813,7 @@ replacementForClass(Class c)
{
if (paths != 0) NSFreeMapTable(paths);
RELEASE(iLock);
RELEASE(changes);
[super dealloc];
}
@ -846,13 +863,12 @@ replacementForClass(Class c)
return self;
}
- (void) setChange: (NSDictionary *)info forKey: (NSString *)key
- (void) setChange: (NSMutableDictionary *)info forKey: (NSString *)key
{
[changes setValue: info forKey: key];
}
- (NSDictionary *) changeForKey: (NSString *)key
- (NSMutableDictionary *) changeForKey: (NSString *)key
{
return [changes valueForKey: key];
}
@ -1056,7 +1072,8 @@ replacementForClass(Class c)
{
id oldValue;
oldValue = [observedObjectForForwarding valueForKey: keyForForwarding];
oldValue
= [observedObjectForForwarding valueForKey: keyForForwarding];
[observedObjectForForwarding removeObserver: self forKeyPath:
keyForForwarding];
if (oldValue)
@ -1076,7 +1093,8 @@ replacementForClass(Class c)
| NSKeyValueObservingOptionOld
context: target];
//prepare change notification
newValue = [observedObjectForForwarding valueForKey: keyForForwarding];
newValue
= [observedObjectForForwarding valueForKey: keyForForwarding];
if (newValue)
{
[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
{
GSKVOInfo *info;
@ -1325,13 +1338,32 @@ replacementForClass(Class c)
id old;
NSMutableDictionary *change;
change = [NSMutableDictionary dictionary];
change = [info changeForKey: aKey];
if (change == 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)
if (old == nil)
{
[change removeObjectForKey: NSKeyValueChangeOldKey];
}
else
{
[change setObject: old forKey: NSKeyValueChangeOldKey];
}
[info setChange: change forKey: aKey];
}
else
{
[change setObject: old forKey: NSKeyValueChangeOldKey];
}
[change removeObjectForKey: NSKeyValueChangeNewKey];
[change removeObjectForKey: NSKeyValueChangeKindKey];
}
[self willChangeValueForDependentsOfKey: aKey];
}
@ -1350,9 +1382,7 @@ replacementForClass(Class c)
forKey: NSKeyValueChangeNewKey];
[change setValue: [NSNumber numberWithInt: NSKeyValueChangeSetting]
forKey: NSKeyValueChangeKindKey];
[info notifyForKey: aKey ofChange: change];
[info setChange: nil forKey: aKey];
}
[self didChangeValueForDependentsOfKey: aKey];
}
@ -1384,7 +1414,6 @@ replacementForClass(Class c)
}
[info notifyForKey: aKey ofChange: change];
[info setChange:nil forKey: aKey];
}
[self didChangeValueForDependentsOfKey: aKey];
}
@ -1397,10 +1426,10 @@ replacementForClass(Class c)
info = [self observationInfo];
{
NSDictionary *change;
NSMutableDictionary *change;
NSMutableArray *array;
change = [NSMutableDictionary dictionary];
change = [[NSMutableDictionary alloc] initWithCapacity: 1];
array = [self valueForKey: aKey];
if (changeKind == NSKeyValueChangeRemoval
@ -1411,6 +1440,7 @@ replacementForClass(Class c)
}
[info setChange: change forKey: aKey];
RELEASE(change);
}
[self willChangeValueForDependentsOfKey: aKey];
}
@ -1424,14 +1454,15 @@ replacementForClass(Class c)
info = [self observationInfo];
if (info != nil)
{
NSDictionary *change;
NSMutableDictionary *change;
NSMutableSet *set;
change = [NSMutableDictionary dictionary];
change = [[NSMutableDictionary alloc] initWithCapacity: 1];
set = [self valueForKey: aKey];
[change setValue: [set mutableCopy] forKey: @"oldSet"];
[info setChange: change forKey: aKey];
RELEASE(change);
}
[self willChangeValueForDependentsOfKey: aKey];
}
@ -1485,7 +1516,6 @@ replacementForClass(Class c)
[change setValue: new forKey: NSKeyValueChangeNewKey];
}
[info notifyForKey: aKey ofChange: change];
[info setChange:nil forKey: aKey];
}
[self didChangeValueForDependentsOfKey: aKey];
}