Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add removeObserver:fromObjectsAtIndexes:forKeyPath:context: method #330

Merged
merged 7 commits into from
Oct 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ Tests/base/*/GNUmakefile
*.log
*.sum

# Unit test byproducts
*.err
*.out

# Autoconf
autom4te.cache

Expand Down
9 changes: 9 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -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
Expand Down
6 changes: 6 additions & 0 deletions Headers/Foundation/NSKeyValueObserving.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

/**
Expand Down
19 changes: 19 additions & 0 deletions Source/NSKeyValueObserving.m
Original file line number Diff line number Diff line change
Expand Up @@ -1687,6 +1687,25 @@ - (void) removeObserver: (NSObject*)anObserver
}
}

- (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

/**
Expand Down
95 changes: 93 additions & 2 deletions Tests/base/KVC/mutable.m
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,56 @@
} aStruct;

@interface Observer : NSObject
{
NSMutableSet *_keysChanged;
}

- (void) reset;

- (NSSet *) keysChanged;

- (void) observeValueForKeyPath: (NSString *)keyPath
ofObject: (id)object
change: (NSDictionary *)change
context: (void *)context;
@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
context: (void *)context
{
NSLog(@"observeValueForKeyPath: %@\nofObject:%@\nchange:%@\ncontext:%p",
keyPath, object, change, context);

[_keysChanged addObject: keyPath];
}
@end

Expand All @@ -31,6 +67,7 @@ @interface Lists : NSObject
NSMutableArray * numbers;
NSMutableArray * third;
NSString *string;
NSString *string2;
aStruct x;
}

Expand Down Expand Up @@ -115,6 +152,16 @@ - (void) setX: (aStruct)s
x = s;
}

- (void) setString2: (NSString *)s
{
string2 = s;
}

- (NSString *) string2
{
return string2;
}

- (void) willChangeValueForKey: (NSString*)k
{
[super willChangeValueForKey: k];
Expand Down Expand Up @@ -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]],
Expand Down Expand Up @@ -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;
}