2009-11-25 4 views
0

J'ai une vue qui est ajoutée en tant que sous-vue dans un viewcontroller. La sous-vue a des méthodes délégués et le viewcontroller est associé à son délégué. La sous-vue possède une animation et appelle une méthode déléguée lorsque l'animation est terminée. Le problème est que lorsque le contrôleur de vue est retiré de la vue par le contrôleur de navigation, la sous-vue n'est pas libérée. Probablement parce que le nombre de versions est> 0. Lorsque le viewcontroller est retiré de la vue avant la fin de l'animation de sous-vue, la sous-vue tente d'appeler la méthode delegate (qui est le viewcontroller qui n'existe plus) et j'obtiens un EXC_BAD_ACCESS.UIView n'est pas libéré. Appel de délégué avec self, et en utilisant UIView commitAnimations ajoute le nombre de retenue

Peut-être un échantillon clarifier les choses;):

La vue

- (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{ 

} 

J'ai découvert qu'après la

[UIView commitAnimations]; 

ligne le retainCount la vue est 2, et après le

[delegate viewWasAnimated:self]; 

le nombre de versions est 3. Donc c'est probablement pourquoi la vue n'est pas libérée. Je sais que je ne suis pas censé regarder les comptes de retenue, mais je ne sais pas quoi faire d'autre.

Répondre

1

Votre vue n'est pas désaffectée car le bloc UIViewbeginAnimation le conserve pendant toute la durée de l'animation. Donc, si votre contrôleur peut être libéré lors de votre animation, vous pouvez supprimer le UIView de la vue dans le dealloc et la vérification de la méthode animationDidStop: du contrôleur si le superview est égal à zéro si oui, alors ne pas envoyer le 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]; 
    } 
} 

Une autre approche que vous pourriez prendre est d'annuler l'animation UIView mais ce n'est pas aussi intuitif.

Dans la méthode dealloc du UIViewController do

[UIView beginAnimations:nil context:NULL]; 
[UIView setAnimationBeginsFromCurrentState:YES]; 
[UIView commitAnimations]; 

Ceci annulera les animations en cours. Et vous recevrez finished == NO dans le animationDidStop un message

(void)viewDidAnimate:(NSString *)animationID finished:(BOOL)finished context:(void *)context{ 
    if (finished && self.delegate != NULL && [self.delegate respondsToSelector:@selector(viewWasAnimated:)]) { 
    [delegate viewWasAnimated:self]; 
    } 
} 
+0

D'accord c'est ce que je pensais. J'ai ajouté le chèque pour voir si l'aperçu est nul. Cela a résolu un problème que j'ai. Je suppose que l'animation UIView libère ma vue quand c'est fait. Toujours le [délégué viewWasAnimated: self]; L'appel ajoute un compte de retenue afin que la vue ne soit jamais libérée. –

+0

Définissez-vous le délégué avec retain ou assign dans la déclaration @property. Assurez-vous de le déclarer comme assign, car vous créerez une boucle de conservation si vous ne le faites pas. Puisque le délégué sera retenu par le point de vue et que le point de vue est conservé par le délégué, aucun des points ne sera jamais publié. Vous pouvez facilement voir qui retient votre point de vue si vous ne pouvez pas comprendre en remplaçant les méthodes suivantes sur MyView et la fixation d'un point de rupture pour voir qui fait Retain et la libération des appels - (id) retenir { return [super retain]; } - (vide) libération { [super release]; } Bonne chance! –

+0

Le délégué a été déclaré comme assing. Mais grâce aux appels de libération retenus, j'ai découvert que j'avais aussi une minuterie qui retenait la vue. J'ai ajouté une fonction [myview cancelTimer] qui invalide le timer. J'appelle cette fonction dans les méthodes viewWillDisappear du viewcontroller contenant myview. Cela a fait l'affaire. Merci! –

0

Tout d'abord je pense que c'est une faute de frappe, mais:

[self.view addSubview:adview]; 

devrait être

[self.view addSubview:myview]; 

A propos de votre question:

1-Put MyView * myview; dans votre viewcontroller.h

2 Avant de relâcher le viewcontroller, appelez:

[myview removeFromSuperView]; 

Cela devrait liberer votre sous-vue (s'il n'y a pas d'autres supplémentaires conserve)

Bonne chance..

+0

J'ai ajouté myview à la vue de la viewcontroller puis il a publié. myview n'est alors retenu que par le self.view du viewcontroller. Une fois le self.view libéré, toutes les sous-vues sont également libérées. Oui c'était un type :). –

Questions connexes