如何安全地从 NSMutableSet 中删除对象 (cocos2d-iphone)
我对严肃的编程相当陌生,所以请原谅我的愚蠢,但我自己没能弄清楚这一点。
我正在用 cocos2d-iphone 编写一个游戏。我有一个场景对象,其 ivars 中有多个 NSMutableSets - 单位、建筑物、火箭等。我在从这些 NSMutableSets 中删除对象时遇到问题。当子弹对象被初始化时,它会像这样搜索应该损坏的目标:
...
for ( RXUnit * unit in targetSet ) {
if ( ccpDistance( unit.position, rayPoint ) < 20 ) {
...
[unit damageSelfBy:damage];
...
}
}
...
如果单位没有足够的 HP 来维持,则 [unit DamageSelfBy:damage]
方法会杀死该单位损害。除其他外,它还执行以下操作:
[scene.units removeObject:self];
(scene.units 与上面循环中的 targetSet 是相同的 NSMutableSet)
每当使用此行时,从集合中删除单位时发射的子弹无法正确初始化。项目符号 init 方法执行到上面所示的 for 循环(是的,该单元确实被前一个项目符号损坏并移除),但 init 方法中此循环之后的任何其他内容都不会执行。
令人惊讶的是,应用程序继续正常运行,除了卡住的子弹之外没有任何可见的影响。控制台不显示任何警告/错误,编译时也没有警告。
我还尝试通过将实际的删除代码放入场景的更新方法中来延迟单元从集合中删除的时间,但这没有帮助。
我想我可以做一些丑陋的黑客来隐藏这个问题,但我相信它稍后会咬我的屁股。好吧,我真的很想了解发生了什么以及如何正确解决它。
非常感谢任何帮助/想法。也许我什至不应该将游戏对象存储在 NSMutableSets 中?
I'm rather new to serious programming, so please forgive my dumbness, but I've failed to figure this out by myself.
I am writing a game with cocos2d-iphone. I have a scene object with several NSMutableSets in its ivars - units, buildings, rockets, etc. I have a problem removing objects from these NSMutableSets. When a bullet object is init-ed it among other things searches for a target that it should damage like this:
...
for ( RXUnit * unit in targetSet ) {
if ( ccpDistance( unit.position, rayPoint ) < 20 ) {
...
[unit damageSelfBy:damage];
...
}
}
...
The [unit damageSelfBy:damage]
method kills the unit if it does not have enough HP to sustain damage. Among other things it does this:
[scene.units removeObject:self];
(scene.units is the same NSMutableSet as targetSet in the loop above)
Whenever this line is used, the bullet that was shot at the time the unit is being removed from the set fails to init properly. The bullet init method executes up to the for loop shown above (yes, the unit does get damaged and removed by previous bullet), but anything else that goes after this loop in the init method is just not executed.
Surprisingly, the application continues to run normally with no visible effects apart from that stuck bullet. Console does not show any warnings/errors, there are no warnings when compiling either.
I also tried delaying the time the unit is removed from the set by putting the actual removal code in the scene's update method, but that does not help.
I think I can make some ugly hacks to hide this problem, but I'm sure it will bite me in the ass later. And well, I would really like to understand what is going on and how to properly address it.
Any help/ideas are much appreciated. Maybe I shouldn't even store game objects in NSMutableSets?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
set 容器是对象的唯一引用吗?如果您在运行对象的方法时释放对象,我不确定是否存在已定义的行为。您可能需要将其标记为“死亡”,然后执行清理步骤。
Is the set container the only reference to the object? I'm not sure that there is a defined behavior if you dealloc an object while you're running its methods. You may need to mark it as "dead" and then do a cleanup step afterward.
如果您从集合中删除该对象,并且该集合是对该对象的唯一引用,则该对象可以立即被释放。想一想:您正在运行其方法的对象可能立即消失。这很糟糕™。
这就是为什么你的延迟删除有效;这不是一个诡计。您需要等待,直到使用完该对象,然后删除它。不过,有一个比您的
objectsToRemove
技巧更好的方法:autorelease
将导致在运行循环时将延迟的release
消息发送到您的对象完成,因此通过使用retain
,然后使用autorelease
,可以防止对象在从scene.units
中删除后消失。If you remove the object from the set, and that set is the only reference to the object, then the object could be deallocated right then. Think for a second: the object whose methods you're running could disappear right now. That's Bad™.
That's why your delayed removal works; it's not a trick. You're waiting until you've finished using the object, then you're deleting it. There's a better way, though, than your
objectsToRemove
trick:autorelease
will cause a delayedrelease
message to be sent to your object when the run loop finishes, so by usingretain
, thenautorelease
, you prevent the object from disappearing the second it's removed fromscene.units
.