mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-22 16:33:29 +00:00
Merge pull request #330 from gnustep/NSKeyValueObserving_issue327
This commit is contained in:
commit
e58b83c1f3
5 changed files with 130 additions and 1 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -9,6 +9,10 @@ Tests/base/*/GNUmakefile
|
|||
*.log
|
||||
*.sum
|
||||
|
||||
# Unit test byproducts
|
||||
*.err
|
||||
*.out
|
||||
|
||||
# Autoconf
|
||||
autom4te.cache
|
||||
|
||||
|
|
|
@ -1,3 +1,12 @@
|
|||
2023-10-07 Gregory John Casamento <greg.casamento@gmail.com>
|
||||
|
||||
* Headers/Foundation/NSKeyValueObserving.h
|
||||
* Source/NSKeyValueObserving.m: Add nethods
|
||||
removeObserver:forKeyPath:context: and
|
||||
removeObserver:forObjectsAtIndexes:forKeyPath:context:
|
||||
* Tests/base/KVC/mutable.m: Add tests for the above
|
||||
methods.
|
||||
|
||||
2023-08-18 Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
||||
* Headers/Foundation/NSCache.h: Add _lock ivar
|
||||
|
|
|
@ -157,6 +157,12 @@ GS_EXPORT NSString *const NSKeyValueChangeNotificationIsPriorKey;
|
|||
fromObjectsAtIndexes: (NSIndexSet*)indexes
|
||||
forKeyPath: (NSString*)aPath;
|
||||
|
||||
#if OS_API_VERSION(MAC_OS_X_VERSION_10_7,GS_API_LATEST)
|
||||
- (void) removeObserver: (NSObject*)anObserver
|
||||
fromObjectsAtIndexes: (NSIndexSet *)indexes
|
||||
forKeyPath: (NSString*)aPath
|
||||
context: (void *)context;
|
||||
#endif
|
||||
@end
|
||||
|
||||
/**
|
||||
|
|
|
@ -1687,6 +1687,25 @@ cifframe_callback(ffi_cif *cif, void *retp, void **args, void *user)
|
|||
}
|
||||
}
|
||||
|
||||
- (void) removeObserver: (NSObject*)anObserver
|
||||
fromObjectsAtIndexes: (NSIndexSet *)indexes
|
||||
forKeyPath: (NSString*)aPath
|
||||
context: (void *)context
|
||||
{
|
||||
NSUInteger i = [indexes firstIndex];
|
||||
|
||||
while (i != NSNotFound)
|
||||
{
|
||||
NSObject *elem = [self objectAtIndex: i];
|
||||
|
||||
[elem removeObserver: anObserver
|
||||
forKeyPath: aPath
|
||||
context: context];
|
||||
|
||||
i = [indexes indexGreaterThanIndex: i];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
/**
|
||||
|
|
|
@ -8,6 +8,14 @@ typedef struct {
|
|||
} aStruct;
|
||||
|
||||
@interface Observer : NSObject
|
||||
{
|
||||
NSMutableSet *_keysChanged;
|
||||
}
|
||||
|
||||
- (void) reset;
|
||||
|
||||
- (NSSet *) keysChanged;
|
||||
|
||||
- (void) observeValueForKeyPath: (NSString *)keyPath
|
||||
ofObject: (id)object
|
||||
change: (NSDictionary *)change
|
||||
|
@ -15,6 +23,32 @@ typedef struct {
|
|||
@end
|
||||
|
||||
@implementation Observer
|
||||
- (instancetype) init
|
||||
{
|
||||
self = [super init];
|
||||
if (self)
|
||||
{
|
||||
_keysChanged = [[NSMutableSet alloc] init];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
RELEASE(_keysChanged);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void) reset;
|
||||
{
|
||||
[_keysChanged removeAllObjects];
|
||||
}
|
||||
|
||||
- (NSSet *) keysChanged
|
||||
{
|
||||
return _keysChanged;
|
||||
}
|
||||
|
||||
- (void) observeValueForKeyPath: (NSString *)keyPath
|
||||
ofObject: (id)object
|
||||
change: (NSDictionary *)change
|
||||
|
@ -22,6 +56,8 @@ typedef struct {
|
|||
{
|
||||
NSLog(@"observeValueForKeyPath: %@\nofObject:%@\nchange:%@\ncontext:%p",
|
||||
keyPath, object, change, context);
|
||||
|
||||
[_keysChanged addObject: keyPath];
|
||||
}
|
||||
@end
|
||||
|
||||
|
@ -31,6 +67,7 @@ typedef struct {
|
|||
NSMutableArray * numbers;
|
||||
NSMutableArray * third;
|
||||
NSString *string;
|
||||
NSString *string2;
|
||||
aStruct x;
|
||||
}
|
||||
|
||||
|
@ -115,6 +152,16 @@ typedef struct {
|
|||
x = s;
|
||||
}
|
||||
|
||||
- (void) setString2: (NSString *)s
|
||||
{
|
||||
string2 = s;
|
||||
}
|
||||
|
||||
- (NSString *) string2
|
||||
{
|
||||
return string2;
|
||||
}
|
||||
|
||||
- (void) willChangeValueForKey: (NSString*)k
|
||||
{
|
||||
[super willChangeValueForKey: k];
|
||||
|
@ -179,11 +226,17 @@ int main(void)
|
|||
NSMutableArray * proxy;
|
||||
NSDictionary * temp;
|
||||
|
||||
[observer reset];
|
||||
[list addObserver: observer forKeyPath: @"numbers" options: 15 context: 0];
|
||||
[list addObserver: observer forKeyPath: @"string" options: 15 context: 0];
|
||||
[list addObserver: observer forKeyPath: @"string2" options: 15 context: 0];
|
||||
[list addObserver: observer forKeyPath: @"x" options: 15 context: 0];
|
||||
|
||||
[list setValue: @"x" forKey: @"string"];
|
||||
[list setString2: @"Hello"];
|
||||
|
||||
PASS([[observer keysChanged] containsObject: @"string2"],
|
||||
"string2 did change properly");
|
||||
|
||||
proxy = [list mutableArrayValueForKey:@"numbers"];
|
||||
PASS([proxy isKindOfClass:[NSMutableArray class]],
|
||||
|
@ -277,8 +330,46 @@ int main(void)
|
|||
|
||||
[list removeObserver: observer forKeyPath: @"numbers"];
|
||||
[list removeObserver: observer forKeyPath: @"string"];
|
||||
[list removeObserver: observer forKeyPath: @"x"];
|
||||
[list removeObserver: observer forKeyPath: @"x"];
|
||||
[list removeObserver: observer forKeyPath: @"string2" context: 0];
|
||||
|
||||
// Test if we see the change on string2 after the observer is removed with
|
||||
// the removeObjserver:forKeyPath:context: method.
|
||||
[observer reset];
|
||||
[list setString2: @"Test"];
|
||||
PASS([[observer keysChanged] containsObject: @"string2"] == NO,
|
||||
"string2 should NOT have been observed");
|
||||
|
||||
// Create an array and add an object, add an observer to that object... test
|
||||
// it and then remove it and verify the remove.
|
||||
Lists *obj = [[[Lists alloc] init] autorelease];
|
||||
NSArray *array = [NSArray arrayWithObject: obj];
|
||||
NSIndexSet *idxs = [NSIndexSet indexSetWithIndex: 0];
|
||||
|
||||
// Add the observer then remove it...
|
||||
[observer reset];
|
||||
[array addObserver: observer
|
||||
toObjectsAtIndexes: idxs
|
||||
forKeyPath: @"string2"
|
||||
options: 15
|
||||
context: 0];
|
||||
|
||||
[obj setString2: @"Hello again"];
|
||||
PASS([[observer keysChanged] containsObject: @"string2"],
|
||||
"string2 has been observed");
|
||||
|
||||
[observer reset];
|
||||
[array removeObserver: observer
|
||||
fromObjectsAtIndexes: idxs
|
||||
forKeyPath: @"string2"
|
||||
context: 0];
|
||||
|
||||
// Determine if it still responds..
|
||||
[obj setString2: @"Test"];
|
||||
PASS([[observer keysChanged] containsObject: @"string2"] == NO,
|
||||
"string2 should NOT have been observed");
|
||||
|
||||
|
||||
[arp release]; arp = nil;
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue