问题
Solved. Ridiculously embarrassing. I wasn't using an instance variable, I declared it outside of curly braces in the implementation.
Really struggling. I have a view controller that manages an animated countdown timer. The animation is using recursive UIView animation and a simple int ivar that gets decremented. Something like the following (this is a simplified snippet):
- (void) animate {
[UIView animateWithDuration:0.75f
delay:0.25f
options:UIViewAnimationCurveEaseInOut
animations:^{ aView.center = newCenter;
counter--; }
completion:^(BOOL finished) {
if (counter != 0) [self animate]; }];
}
During the countdown the user can swipe to go to the next step rather than wait for the timer to finish the countdown. When the user swipes a new view controller -- a new instance of the current view controller -- is pushed on the stack with the values for the next step:
TimerViewController * vc = (TimerViewController*)[self.storyboard instantiateViewControllerWithIdentifier:@"Timer"];
[vc setTask: _task + 1];
[self.navigationController pushViewController:vc animated:YES];
The new view controller slides into place and begins to countdown, but the previous view controller continues to animate, in the debugger I can clearly see the other instance of this view controller, the one I would pop to get back to, is still running its animation, which causes aView to move erratically. The two different view controller instances are animating the same aView instance?
How can I stop the animation from the previous view controller in the stack? I am setting counter = 0
in viewWillDisappear
and all kinds of other desperate things to no avail, I am missing what is really at play here.
Really appreciate any help.
UPDATE 1 (adding viewWillDisappear
implemenation):
-(void) viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
counter = 0;
}
UPDATE 2 (edited to show the instance)
I verified the obvious, that there are multiple TimerViewController instances with their own aView instances. I added logging during the animations
block to show the current instance, task and counter values.
2012-11-03 10:28:19.930 develop.[4362:907] [0x1f5a38f0]NiceTimer:viewWillAppear
2012-11-03 10:28:19.940 develop.[4362:907] [0x1f5a38f0](0)>03:00
2012-11-03 10:28:21.149 develop.[4362:907] [0x1f5a38f0](0)>02:59
2012-11-03 10:28:22.161 develop.[4362:907] [0x1f5a38f0](0)>02:58
2012-11-03 10:28:23.170 develop.[4362:907] [0x1f5a38f0](0)>02:57
2012-11-03 10:28:24.183 develop.[4362:907] [0x1f5a38f0](0)>02:56
2012-11-03 10:28:25.210 develop.[4362:907] [0x1f5a38f0](0)>02:55
2012-11-03 10:28:26.221 develop.[4362:907] [0x1f5a38f0](0)>02:54
2012-11-03 10:28:26.694 develop.[4362:907] ---swipe---
2012-11-03 10:28:26.698 develop.[4362:907] delegate:niceTimerViewControllerDidSwipe:duringTask
2012-11-03 10:28:26.713 develop.[4362:907] [0x1f5a38f0]NiceTimer:viewWillDisappear
2012-11-03 10:28:26.715 develop.[4362:907] [0x1f5b0ac0]NiceTimer:viewWillAppear
2012-11-03 10:28:26.720 develop.[4362:907] [0x1f5b0ac0](1)>02:00
2012-11-03 10:28:27.096 develop.[4362:907] [0x1f5a38f0]NiceTimer:viewDidDisappear
2012-11-03 10:28:27.099 develop.[4362:907] [0x1f5a38f0](0)>01:59
2012-11-03 10:28:27.748 develop.[4362:907] [0x1f5b0ac0](1)>01:58
2012-11-03 10:28:27.754 develop.[4362:907] [0x1f5a38f0](0)>01:57
2012-11-03 10:28:28.754 develop.[4362:907] [0x1f5b0ac0](1)>01:56
2012-11-03 10:28:28.763 develop.[4362:907] [0x1f5a38f0](0)>01:55
2012-11-03 10:28:29.764 develop.[4362:907] [0x1f5b0ac0](1)>01:54
2012-11-03 10:28:29.770 develop.[4362:907] [0x1f5a38f0](0)>01:53
2012-11-03 10:28:30.542 develop.[4362:907] ---swipe---
2012-11-03 10:28:30.545 develop.[4362:907] delegate:niceTimerViewControllerDidSwipe:duringTask:1
2012-11-03 10:28:30.560 develop.[4362:907] [0x1f5b0ac0]NiceTimer:viewWillDisappear
2012-11-03 10:28:30.562 develop.[4362:907] [0x1f5ac3d0]NiceTimer:viewWillAppear
2012-11-03 10:28:30.567 develop.[4362:907] [0x1f5ac3d0](2)>05:00
2012-11-03 10:28:30.593 develop.[4362:907] [0x1f5a38f0](0)>04:59
2012-11-03 10:28:30.601 develop.[4362:907] [0x1f5a38f0](0)>04:58
2012-11-03 10:28:30.617 develop.[4362:907] [0x1f5a38f0](0)>04:57
2012-11-03 10:28:30.620 develop.[4362:907] [0x1f5a38f0](0)>04:56
Sorry for so long but this really shows what is going on. After a swipe there is the push (code at the top of the post). I would expect the task to increment (0)> go to (1)> and remain constant until the next swipe. Instead I am seeing each previous instance on the stack continue to fire, using the value of the current counter. Each previous instance's animation continues against the current counter
UPDATE 3
I implemented a delegate that gets called in the swipe handler, TVC1 is the delegate that gets passed to TVC2, etc, when pushed. The delegate sets counter to 0, called removeAllAnimations, etc, and no effect. I really thought this would do it. At this point I think I am going down the wrong path trying to solve it in the manner. Made a new project, trivial implementation, to make sure it wasn't something else in the app.
-(void)timerViewControllerDidSwipe:(TimerViewController *)controller duringTask:(int)task {
NSLog(@"timerViewControllerDidSwipe:duringTask:%d", task);
counter = 0;
[self.aView.layer removeAllAnimations];
[self.view.layer removeAllAnimations];
aView = nil;
// This is showing everything I tried
}
UPDATE 4
I found the issue! All instances refer to the same int. I don't know how this is possible, ints are not specific to an instance of a class??
2012-11-03 13:16:49.336 develop.[4656:907] [animate:0x1ed8c790](1)>02:46
2012-11-03 13:16:49.340 develop.[4656:907] **[^anim:0x1ed8c790](1)>166(duration=0x6a748)**
2012-11-03 13:16:49.344 develop.[4656:907] [^after:0x1eddb8c0](0)>166
2012-11-03 13:16:49.352 develop.[4656:907] [animate:0x1eddb8c0](0)>02:45
2012-11-03 13:16:49.356 develop.[4656:907] **[^anim:0x1eddb8c0](0)>165(duration=0x6a748)**
回答1:
Before you push the TimerViewController on to the navigation stack, try removing all running Animations:
[aView.layer removeAllAnimations];
TimerViewController * vc = (TimerViewController*)[self.storyboard instantiateViewControllerWithIdentifier:@"Timer"];
[vc setTask: _task + 1];
[self.navigationController pushViewController:vc animated:YES];
Also, make sure you've imported <QuartzCore/QuartzCore.h>
or you'll get the following error: Receiver type 'CALayer' for instance message is a forward declaration
回答2:
Fixed. Could not be more embarrassed. Basic syntax issue. I did not enclose the variable declarations within curly braces. I did this:
@implementation TimerViewController
int counter;
- (void) aMethod { }
@end
Instead of this:
@implementation TimerViewController {
int counter;
}
- (void) aMethod { }
@end
I hope my error will help someone! It never would have occurred to me. A mistake I will not make again.
来源:https://stackoverflow.com/questions/13202574/uiview-animation-continues-to-run-after-a-new-view-controller-is-pushed-onto-the