2013-04-09 3 views
1

J'utilise un UIWebView, et il affiche une alerte lorsqu'un bouton est cliqué (à partir de javascript). Il y a un autre bouton (dans le côté natif), qui ferme le contrôleur, donc deallocs également UIWebView. Le problème est que, si je touche le bouton dans UIWebView, et que j'appuie sur le bouton de fermeture avant que l'alerte ne soit remplie, mon contrôleur et UIWebView sont libérés, mais l'alerte reste à l'écran. Ensuite, si je clique sur un bouton d'alerte, application se bloque et donne l'erreur suivante:Zombie UIWebView quand il est désalloué juste après alert() appelé de javascript

[UIWebView modalView:didDismissWithButtonIndex:]: message sent to deallocated instance 

Et cette méthode est appelée méthode privée

[UIModalView(Private) _popoutAnimationDidStop:finished:] 

J'utilise ARC, et mon dealloc est comme ça :

- (void)dealloc { 
    [_myWebView stopLoading]; 
    _myWebView.delegate = nil; 
    _myWebView = nil; 
} 

Mais cela ne résout pas mon problème parce que je pense UIModalView a une référence de mon WebView en tant que délégué, et je ne pouvais pas le mettre à zéro parce que son privé.

Comment puis-je le résoudre?

Cordialement

Répondre

1

Trouver un moyen de mettre le délégué sur UIAlertView à zéro avant désaffecter UIWebView.

+0

Je ne peux pas accéder à UIAlertView car il est géré par UIWebView en privé. – manuyavuz

+0

Vous pouvez raccorder la fonction déléguée UIAlertView. Vous pouvez donc conserver UIWebView pour l'empêcher de sortir trop tôt. –

1

Ceci est un bug Apple dans leur gestion de la vue d'alerte. Open a bug report.

En attendant, voici quelques solutions de contournement:

Créer une catégorie sur UIAlertView:

@interface UIAlertView (QuickDismiss) @end 

@implementation UIAlertView (QuickDismiss) 


- (void)__quickDismiss 
{ 
    [self dismissWithClickedButtonIndex:self.cancelButtonIndex animated:NO]; 
} 

@end 

Maintenant, à votre avis la méthode dealloc de commande, appelez ceci:

[[UIApplication sharedApplication] sendAction:@selector(__quickDismiss) to:nil from:nil forEvent:nil]; 

Cela supprimera toutes les vues d'alerte actuellement ouvertes, y compris celles affichées par votre vue Web.

Si cela ne fonctionne pas, vous pouvez toujours itérer toutes les sous-vues de tous les objets UIApplication.sharedApplication.windows, en vérifiant si [view.class.description hasPrefix:@"UIAlertView"] est vrai et en ignorant cela. C'est une méthode moins élégante que la précédente et devrait être utilisée en dernier recours.

Bonne chance.

0

Enfin, je trouve une solution géniale qui fonctionne bien. J'utilise la méthode swizzle pour accrocher la fonction UIAlertView délégué - (void) didPresentAlertView: (UIAlertView *) alertView

- (void)didPresentAlertView:(UIAlertView *)alertView 
{ 
    if ([self.delegate respondsToSelector:@selector(didPresentAlertView:)]) { 
     [self.delegate didPresentAlertView:alertView]; 
    } 
    if ([self.delegate isKindOfClass: [UIWebView class]]) { 
     uiWebView = self.delegate; 
    } 
} 

Je retiens simplement par exemple UIWebView dans cette fonction afin que l'instance UIWebView en tant que délégué de UIAlertView ne sera pas libéré avant UIAlertView instance étant libéré.

Questions connexes