I have a situation where troops can attack buildings. Each troop keeps a pointer to its target.
@property (nonatomic, weak) Building *target;
In an update loop, the troops periodically cause damage to their 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 */
The problem is:
troop1deals the blow that fellsbuilding1and moves on tobuilding2troop2was attackingbuilding1but waits until its next attack to determine thatbuilding1is nownil.
I realise the problem is that troop2‘s pointer has not been set to nil and instead I should be checking that the value of the pointer is nil.
I tried using if (*_target) but was met with the message
Statement requires expression of scalar type
If there a way to achieve this kind of comparison in Objective-C? What other options are there for determining when a value has changed? KVO? Some extensive delegate pattern?
It is the pointer itself that is set to nil when the object it points to is deallocated.
if (objectPointer == nil)is always the way to check if an object is nil in Objective-C/Cocoa. If the pointer is not nil, it means the object in question has not in fact been deallocated. If you dereference a pointer to an object, you get a struct, hence the compiler error about needing a scalar value in the if expression.So, in your case, if
if(self.target != nil)is not giving you the result you expect, you should look for remaining strong references to the target (from other objects).More broadly, as hinted at by trojanfoe’s answer, you’re relying on ARC’s zeroing weak reference behavior for real program logic. In theory this is OK, as (contrary to his initial statement), ARC’s zeroing weak behavior is reliable/deterministic. But, it does mean that you have to ensure that targets are always deallocated when they’re no longer on the playing field (or whatever). This is a bit fragile. Zeroing weak references are intended as a way to avoid retain cycles (essentially a form of memory leak), rather than as a way to implement logic the way you’re doing. The gist of trojanfoe’s solution, where you explicitly register and unregister targets as necessary, is probably a more robust solution.