UIView isn't released. Calling delegate with self, and using UIView commitAnimations adds retain count

蓝咒 提交于 2020-01-03 05:22:11

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!