I have a small UIView that bounces in a box. I am adding an Instantaneous mode. push. In fact I am adding very many pushes -- 5 or more Hz.
Mystery:
(1) Do I have to removeBehavior???? if so .. when?!? "after" an "instant" ?
(2) Is it that UIPushBehaviorModeInstantaneous is a special case, and you do not have to (or cannot) remove those??
(3) When you addBehavior: does that .. retain?! the UIPushBehavior? Or?? WTF?!
(4) I couldn't seem to find these aspects documented anywhere!
-(void)pushMeRight:(CGFloat)mag
{
if ( self.bounceAnimator == nil ) return;
NSLog(@"...........push me right %.2f", mag);
UIPushBehavior *pushRight = [[UIPushBehavior alloc]
initWithItems:@[self]
mode:UIPushBehaviorModeInstantaneous];
pushRight.magnitude = mag;
pushRight.angle = radians(0); // (NB, 0 is right, 90 is down)
[self.bounceAnimator addBehavior:pushRight];
}
{Note: I simply alloc the UIPushBehavior each time I need one. Note that if you try to use "just one" as a property, it does not work. In fact, Rob explains why below.}
Solution
After extremely extensive testing, we found that Rob's "second" solution, using the .action, is essentially perfect.
Again after vast testing, we would very strongly recommend that the following code, is, really, "the solution", the only way to code repetitive pushes.. Thank goodness for Rob :/
-(void)pushAllUp:(CGFloat)mag
{
if ( self.bounceAnimator == nil ) return;
for ( UIView *pushme in self.subviews )
{
UIPushBehavior *pp =
[[UIPushBehavior alloc]initWithItems:@[ pushme ]
mode:UIPushBehaviorModeInstantaneous];
pp.magnitude = mag;
pp.angle = radians(270); // (NB, 0 is right, 90 is down)
UIPushBehavior __weak *weakPP = pp;
pp.action = ^{ if (!weakPP.active)
[self.bounceAnimator removeBehavior:weakPP];};
[self.bounceAnimator addBehavior:pp];
}
}
In answer to your questions:
Yes, you are adding that
UIPushBehavior
correctly.You technically don't have to call
removeBehavior
for an instantaneous push because the behavior will have itsactive
status turned off as soon as the instantaneous push takes place.Having said that, I'd be inclined to remove the behavior because you're otherwise taking up memory, with the animator maintaining a strong reference to these non-
active
instantaneous push behaviors. (This is easily verified by logging the animator'sbehaviors
property, which is an array of all of the behaviors it is keeping track of.) There might eventually be a performance related issue for it to iterate through all of these non-active
behaviors, too, though I suspect the memory concerns are probably of more significant interest.But unlike other behaviors (e.g.
UISnapBehavior
) which stayactive
, you don't have to worry about lingering instantaneous push behaviors continuing to affect the items to which it was added.They don't "expire", per se, but, yes, they quickly go to an
active
state ofNO
.Yes, when you add a behavior to the animator, the animator will maintain a strong reference to it until you remove the behavior.
Personally, I'd be inclined to remove the behavior after adding it. Because it's instantaneous, the timing of its removal isn't terribly critical, and you could do something as simple as:
Or, you could set up an
action
that removed it for you.