嘿,现在我已经实现了自己的监听模式。 我将使用快速枚举向监听器发送更新。 代码看起来像这样
- (void) updateListeners {
for (id<AProtocol>listener in _listeners)
{
[listener update];
}
并且在监听器中,我实现了AProtocol的方法,即更新。 假设在_listeners中有n个对象,并且m个监听器使得m&lt;当调用侦听器的更新方法时,我想从侦听中删除它。 这个问题是,当快速枚举正在进行时,我无法删除,我将收到错误。 为了使监听器更加动态,以便我们可以在调用update方法时从_listeners中删除监听器,那么解决方案是什么?(我不想使用NSNotificationCenter)
答案 0 :(得分:4)
听起来你现在拥有的是听众自己决定是否应该将其删除,并将其自行删除。这是有问题的,因为(a)如你所说,它会破坏你的枚举,但是(b)因为它是一个棘手的抽象 - 如果运行“update”的对象也不能直接控制监听器列表中的所有权,那么你的设计模式可能会无论如何都会遇到问题。我可能会建议你重新定义这样的更新监听器:
- (BOOL)update
并返回一个BOOL,指示是否应该删除(或保留侦听器,具体取决于您的语义)。然后你可以像这样编写循环:
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];
正如其他人所建议的那样,如果您确实希望允许侦听器在更新过程中自行删除,那么只需迭代集合的本地副本而不是集合本身就足够了。其语法取决于_listeners
是数组,集合还是其他内容,但请参阅其他答案或文档。
答案 1 :(得分:2)
为什么不在数组副本上运行枚举?
for (id<AProtocol>listener in [NSArray arrayWithArray:_listeners])
{
[listener update];
}
然后可以在循环期间安全地修改_listeners
。它比戴维斯解决方案更安全,因为它不会对任何听众的移除产生免疫,而不仅仅是在更新中发生的移除。
答案 2 :(得分:0)
通过常规迭代替换快速迭代并从最后一次开始。
// 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];
}