问题
I have a view that is added as a subview in a viewcontroller. The subview has delegates methods and the viewcontroller is assinged as its delegate. The subview has a animation and calls a delegate method when the animation is finished.
The problem is that when the viewcontroller is removed from the view by the navigationcontroller the subview isn't deallocated. Probably because it's release count is >0. When the viewcontroller is removed from view before the subview animation finishes the subview tries to call the delegate (which is the viewcontroller which doesn't exist anymore) method and i get a EXC_BAD_ACCESS.
Maybe some sample will clarify things ;):
The view
- (void)somefunction {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:@selector(viewDidAnimate:finished:context:)];
[UIView setAnimationDuration:0.3];
self.frame = CGRectMake(0, 320, 320, 47);
[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
[UIView commitAnimations];
}
-(void)viewDidAnimate:(NSString *)animationID finished:(BOOL)finished context:(void *)context{
if (self.delegate != NULL && [self.delegate respondsToSelector:@selector(viewWasAnimated:)]) {
[delegate viewWasAnimated:self];
}
}
viewcontroller
- (void)viewDidLoad{
[super viewDidLoad];
MYView *myview = [[MYView alloc] init];
myview.delegate = self;
[self.view addSubview:myview];
[myview release];
}
- (void)viewWasAnimated:(MYView *)view{
}
I found out that after the
[UIView commitAnimations];
line the retainCount of the view is 2, and after the
[delegate viewWasAnimated:self];
the release count is 3. So this is probably why the view isn't released. I know I am not supposed to look at retain counts but don't know what else to do.
回答1:
Your view is not deallocated because the UIView
beginAnimation
Block retains it for the whole animation duration. So if your controller can be released during your animation you can remove the UIView
from the controller's view in the dealloc and in the animationDidStop:
method check if the superview is equal to nil if so, then don't send the message
-(void)viewDidAnimate:(NSString *)animationID finished:(BOOL)finished context:(void *)context{
if (self.superview != nil && self.delegate != NULL && [self.delegate respondsToSelector:@selector(viewWasAnimated:)] ) {
[delegate viewWasAnimated:self];
}
}
Another approach you could take is to cancel the UIView
animation but that is not as intuitive.
In the dealloc method of the UIViewController
do
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView commitAnimations];
This will cancel the current animations. And you will receive finished == NO
in the animationDidStop
message
(void)viewDidAnimate:(NSString *)animationID finished:(BOOL)finished context:(void *)context{
if ( finished && self.delegate != NULL && [self.delegate respondsToSelector:@selector(viewWasAnimated:)] ) {
[delegate viewWasAnimated:self];
}
}
回答2:
First off i guess it's a typo but:
[self.view addSubview:adview];
should be
[self.view addSubview:myview];
About your question:
1-Put MYView *myview; in your viewcontroller.h
2-Before you release the viewcontroller, call:
[myview removeFromSuperView];
This should deallocate your subview.(if there are no other additional retains)
Good luck.
来源:https://stackoverflow.com/questions/1797344/uiview-isnt-released-calling-delegate-with-self-and-using-uiview-commitanimat