2010-01-20 5 views
2

Si vous avez appris à la dure que vous devez supprimer le délégué d'un objet si la durée de vie du délégué est plus courte que l'objet. Mais comment faites-vous cela si vous n'avez plus de référence à l'objet?Suppression du délégué sur dealloc de l'objet non référencé

Dans mon application iPhone, j'ai un contrôleur de vue vc qui effectue une activité asynchrone et est affiché en mode modal. Un bouton d'annulation permet de rejeter la vue modale. Si une erreur se produit, un UIAlertView alert est affiché. Si l'utilisateur appuie sur OK, les deux alert et la vue modale disparaissent. Par conséquent vc est défini en tant que délégué pour alert et implémente alertView:didDismissWithButtonIndex:. Quelque chose comme ceci:

// UIViewController vc 
    ... 
    UIAlertView *alert = [[UIAlertView alloc] 
          initWithTitle:@"Error" 
          message:@"Something went wrong" 
          delegate:self 
          cancelButtonTitle:@"OK" 
          otherButtonTitles:nil]; 
    self.alertView = alert; // needed to unset alertView.delegate in dealloc 
    [alert show]; 
    [alert release]; 
    ... 
} 

- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex { 
     [self dismissModalViewControllerAnimated:YES]; 
    } 
} 

Normalement, les blocs d'affichage d'alerte toutes les entrées. Malheureusement, il ne le fait pas dans certains cas. Si l'utilisateur appuie sur le bouton d'annulation avant que la vue d'alerte apparaisse et qu'elle retouche après l'affichage de l'alerte, la vue est ignorée, mais pas l'alerte. vc obtient désalloué et si l'utilisateur tape puis "OK" sur l'alerte, l'application se bloque car un message a été envoyé à l'objet publié.

J'ai résolu cela en affectant alert à une propriété de vc afin que je puisse définir alert.delegate à zéro dans dealloc. Je trouve cette solution pas très élégante, car je n'ai pas vraiment besoin de la référence pour alerter.

Y a-t-il une meilleure approche?

Edit: Ajouté le texte en italique comme clarification

Répondre

2

Donc, si le délégué est vivant lorsque la vue apparaît, il sera probablement en vie quand il est rejeté. Si ce n'est pas le cas, vous devez faire exactement ce que vous avez fait et désactiver manuellement le délégué de la vue d'alerte si vous ne vous souciez plus de son résultat.

Donc, vous vous souciez de l'alertview puisque vous vous souciez de sa méthode de délégation. La ride est que le délégué ne peut pas s'appliquer au moment où l'alerte est rejetée. Vous avez donc besoin de logique, et pour cette logique, vous devez enregistrer une référence à la vue d'alerte en question.

En d'autres termes, vous le faites correctement. Bien que, il peut avoir été utile si UIAlertView a conservé son délégué, mais il ne semble pas le faire s'il se bloque lorsqu'il est ignoré. Enfin, je pensais que la vue d'alerte bloquait toutes les entrées d'écran? Si ce n'est pas le cas, vous pouvez le rendre vraiment modal en définissant vc.view.userInteractionEnabled = NO lorsque l'alerte apparaît et le réactiver lorsqu'il est fermé. De cette façon, l'utilisateur ne peut pas fermer le contrôleur lorsque la vue d'alerte est en hausse. Ce qui me semble un peu plus sain d'esprit.

+0

J'ai essayé réglage userInteractionEnabled = NO mais le Touchup sur le bouton d'annulation est encore traitée. Je vais probablement devoir vivre avec la référence à la manière d'alerte. –

1

Du point de vue de l'interface utilisateur, lorsqu'une vue d'alerte est présent, il doit exiger toute l'attention de l'utilisateur. Peut-être pourriez-vous envisager de désactiver le bouton Annuler (ainsi que tous les autres widgets visibles sans affichage d'alerte) lorsqu'une vue d'alerte est présente et d'ajouter un titre de bouton à l'instance UIAlertView qui effectue la même tâche. Cela fournirait une interface utilisateur plus claire et devrait également résoudre votre problème de mémoire. Bien que normalement, une vue d'alerte est présentée au-dessus du contenu non changeant

0
-(void)delayedDismiss { 
    [self dismissModalViewControllerAnimated:YES]; 
} 

- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex { 
    [self performSelector:@selector(delayedDismiss) withObject:nil afterDelay:0.0]; 

} 
0

Si vous ne se soucient plus des résultats de l'UIAlertView vous devriez probablement rejeter dans le - (void) viewWillDisappear:(BOOL)animated

Questions connexes