2010-09-01 76 views
0

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

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

和听众,我实现方法AProtocol,这是更新。 假设在_listeners中有n个对象,并且m个监听器使得当调用监听器的更新方法时想要将它从自身中删除。 与此问题是,我不能删除快速枚举正在进行时,我会得到一个错误。 为了让听众更加具有动态性,以便我们在调用更新方法时可以从_listeners中删除监听器,那么解决方法是什么?(我不想使用NSNotificationCenter)

回答

4

这听起来像你现在拥有的是听众本身决定是否应该删除它,并删除自己。这是有问题的,因为(a)如你所说,它会打破你的枚举,但(b)因为它是一个棘手的抽象 - 如果运行“update”的对象不能直接控制监听器列表中的所有权,你的设计模式可能会反正遇到问题。我可能会建议您重新定义更新的听众是这样的:

- (BOOL)update 

,并返回一个布尔值,指出侦听器是否应删除(或者保留,这取决于您的语义)。然后,你可以写这样的循环:

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是数组,集合还是其他,但请参阅其他答案或文档。

+0

这个工作很不错。在仿真后删除监听是比较安全的 – 2010-09-08 02:50:41

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]; 
} 
+0

如果'_listeners'不是数组呢? (设置或不太可能的自定义集合。) – 2010-09-01 14:23:03

+0

嗯,我不知道。其实,我认为Ortwin Gentz给出了最好的答案,我不会支持我的回答。我的回答有点破解,你对我看来并不自然。 – David 2010-09-01 14:48:15

2

为什么不在枚举数组的副本上操作枚举?

for (id<AProtocol>listener in [NSArray arrayWithArray:_listeners]) 
{ 
    [listener update]; 
} 

然后_listeners可以在循环过程中安全地修改。它比戴维斯解决方案更安全,因为它不受任何听众移除,不仅仅是发生在更新中的听众。

+0

为什么人们总是使用'[NSArray arrayWithArray:_listeners]'而不是'[_listeners copy]'? – JeremyP 2010-09-01 14:20:51

+0

@JeremyP:我的2美分:我倾向于使用'arrayWithArray'和'setWithSet',因为我通常会发现它更具可读性,因为它很清楚这是一个浅拷贝。你也可以省略内存管理,如果你只是在像这样的一次性上下文中使用它,不像'copy'。 – 2010-09-01 14:24:53

+0

关于内存管理的好处。谢谢。 – JeremyP 2010-09-01 14:43:39