使用快速枚举的侦听器模式的问题

时间:2010-09-01 13:56:04

标签: iphone objective-c cocoa-touch algorithm xcode

嘿,现在我已经实现了自己的监听模式。 我将使用快速枚举向监听器发送更新。 代码看起来像这样

- (void) updateListeners {
for (id<AProtocol>listener in _listeners)
{
   [listener update];
}

并且在监听器中,我实现了AProtocol的方法,即更新。 假设在_listeners中有n个对象,并且m个监听器使得m&lt;当调用侦听器的更新方法时,我想从侦听中删除它。 这个问题是,当快速枚举正在进行时,我无法删除,我将收到错误。 为了使监听器更加动态,以便我们可以在调用update方法时从_listeners中删除监听器,那么解决方案是什么?(我不想使用NSNotificationCenter)

3 个答案:

答案 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];
}