我的情况是部队可以袭击建筑物。每个部队都有一个指向目标的指针。
@property (nonatomic, weak) Building *target;
在更新循环中,部队会定期对目标造成伤害。
if (_target)
{
if (/*enough time has passed since last attack, attack again*/)
{
[_target attack];
if (_target.health <= 0)
{
[_target removeFromParentAndCleanup:YES]; //Cocos2d
_target = nil;
}
}
}
else /* Find new target */
问题是:
troop1
处理building1
落下的打击并转移到building2
troop2
攻击building1
,但等到下一次攻击才确定building1
现在是nil
。我意识到问题是troop2
的指针尚未设置为nil而是我应该检查指针的值是零。
我尝试使用if (*_target)
,但遇到了消息
语句需要表达标量类型
如果有一种方法可以在Objective-C中实现这种比较?还有哪些其他选项可用于确定值何时发生变化?志愿?一些广泛的代表模式?
答案 0 :(得分:4)
当指向的对象被释放时,指针本身被设置为nil。 if (objectPointer == nil)
始终是检查Objective-C / Cocoa中对象是否为零的方法。如果指针不是nil,则意味着有问题的对象实际上没有被释放。如果取消引用指向对象的指针,则会得到一个结构,因此编译器错误需要if表达式中的标量值。
因此,在您的情况下,如果if(self.target != nil)
没有给出您期望的结果,您应该寻找对目标的剩余强引用(来自其他对象)。
更广泛地说,正如trojanfoe的回答所暗示的那样,你依赖于ARC将真实程序逻辑的弱引用行为归零。从理论上讲,这是可以的,因为(与他最初的陈述相反),ARC的归零弱行为是可靠的/确定性的。但是,它确实意味着你必须确保当目标不再在游戏领域(或其他任何方面)时总是解除分配。这有点脆弱。归零弱引用旨在避免保留周期(本质上是一种内存泄漏形式),而不是以您的方式实现逻辑的方式。 Trojanfoe解决方案的要点,您可以根据需要明确注册和取消注册目标,这可能是一个更强大的解决方案。
答案 1 :(得分:2)
我可能会忽略这些内容,但要检查target2
属性是否为nil
,请执行以下操作:
if ( self.target2 == nil ) {
// Something
}
答案 2 :(得分:1)
我认为你过分依赖ARC的实现,因为你只知道如果指针是nil
,是否删除了一个对象。这是不可移植的,你可以在被释放的对象和指针成为 nil
之间做出任何保证吗?
相反,使用对象的中心字典,根据其唯一ID映射并仅存储此唯一ID而不是对象指针本身。在这个例子中,我使用递增整数对密钥使用NSNumber
,但是可能有更好的密钥可以使用。此外,Object
是您要在此字典中存储的任何对象的基类:
// Probably ivars in a singleton class
unsigned _uniqueId = 1;
NSMutableDictionary *_objects;
- (NSNumber *)addObject:(Object *)object
{
NSNumber *key = [NSNumber numberWithUnsignedInt:_uniqueId++];
[_objects setObject:object forKey:key];
return key;
}
- (void)removeObjectForKey:(NSNumber *)key
{
[_objects removeObjectForKey:key];
}
- (Object *)getObjectForKey:(NSNumber *)key
{
return [_objects objectForKey:key];
}
在您的目标中,只需存储构建密钥:
@property (strong) NSNumber *buildingKey;
通过提供的方法获得建筑物:
Building *building = (Building *)[objectDictionary objectForKey:buildingKey];
if (building != nil)
{
// building exists
}
else
{
// building does not exist; throw away the key
buildingKey = nil;
}
答案 3 :(得分:1)
由于target是弱引用,因此假设[_target removeFromParentAndCleanup:YES];
删除了对目标的所有强引用,您的代码应该“按原样”工作。
删除最后一个强引用后,指向它的所有弱属性将自动设置为nil
。如果它们没有自动设置为nil
,那么在某处仍然存在对目标的强烈引用。
查找并删除该引用,这样可以正常工作。