problem with listener pattern using fast enumeration
Hey, right now I have implemented my own listener pattern. I will send an update to the listeners using fast enumeration. the code will look like this
- (void) updateListeners {
for (id<AProtocol>listener in _listeners)
{
[listener update];
}
and in listener, i implement method for AProtocol, which is update. suppose there are n object in _listeners, and m number of listener such that m < n want to remove it self from listen when listener's update method is called. The problem with this is that I can't remove when the fast enumeration is ongoing, I will get an error. In order to make the listener more dynamic so that we can remove listener from _listeners when update method is called, what woul开发者_如何学JAVAd be the solution?( I don't want to use NSNotificationCenter)
It sounds like what you have now is the listener itself deciding whether it should be removed, and removing itself. That's problematic because (a) as you say, it breaks your enumeration, but (b) because it's a tricky abstraction-- if the object that runs "update" doesn't also control ownership in the listener list directly, your design pattern might run into problems anyways. I might suggest that you redefine update listeners like this:
- (BOOL)update
and return a BOOL indicating whether the listener should be removed (or kept, depending on your semantics). Then you could write the loop like this:
NSMutableSet * listenersToBeRemoved = [NSMutableSet set];
for (id<AProtocol> listener in _listeners) {
BOOL shouldRemove = [listener update];
if (shouldRemove) {
[listenersToBeRemoved addObject:listener];
}
}
// Do this if _listeners is a Set, or whatever the equivalent is.
[_listeners minusSet:listenersToBeRemoved];
As others have suggested, if you do want to allow the listeners to remove themselves during the update process, it's simple enough to just iterate through a local copy of the collection, instead of the collection itself. The syntax for that depends on whether _listeners
is an array, a set, or something else, but see other answers or the docs.
Why not operate the enumeration on a copy of the array?
for (id<AProtocol>listener in [NSArray arrayWithArray:_listeners])
{
[listener update];
}
Then _listeners
can safely be modified during the loop. It's safer than Davids solution since it's immune against any listener removals not only the ones that happen in -update.
Replace fast iteration by usual iteration and start from the last.
// must iterate from the last in case the current listener removes itself from the list
for (int i = [_listeners count] - 1; i > -1; i--) {
id<AProtocol> listener = [_listeners objectAtIndex:i];
[listener update];
}
精彩评论