31 votes

Comment arrêter en toute sécurité un UIWebView en cours de chargement dans viewWillDisappear ?

J'ai une vue contenant un UIWebView qui charge une carte google (donc beaucoup de javascript etc). Le problème que j'ai est que si l'utilisateur appuie sur le bouton 'back' de la barre de navigation avant que la vue web n'ait fini de se charger, il n'est pas clair pour moi comment dire à la vue web d'arrêter de se charger et ensuite de la libérer, sans avoir des messages envoyés à l'instance désallouée. Je ne suis pas non plus certain qu'une vue web apprécie que son conteneur disparaisse avant la fin de son chargement (mais je n'ai pas le choix si l'utilisateur appuie sur le bouton "retour" avant que le chargement ne soit terminé).

Dans mon gestionnaire viewWillDisappear, j'ai ceci

map.delegate=nil;
[self.map stopLoading];

cela semble gérer la plupart des cas sans problème, puisque le fait de mettre le délégué à zéro l'empêche d'envoyer le didFailLoadWithError à mon contrôleur de vue. Cependant, si je libère la vue web dans la méthode dealloc de ma vue, il arrive (par intermittence) que je reçoive toujours un message envoyé à l'instance deallocated, qui semble être lié au javascript exécuté dans la page actuelle, par exemple :

-[UIWebView webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:]: message sent to deallocated instance 0x4469ee0

Si je ne libère pas le webview, je n'obtiens pas ces messages, mais je suppose que je libère alors le webview.

Si je n'envoie pas le message "stopLoading" et que je libère simplement le webview dans viewWillDisappear, je vois des messages comme celui-ci :

/SourceCache/WebCore/WebCore-351.9.42/wak/WKWindow.c:250 WKWindowIsSuspendedWindow:  NULL window.

Peut-être lié à cela, j'ai parfois (encore une fois de manière totalement intermittente) un heisenbug hideux où le fait de cliquer sur le bouton retour de la barre de navigation d'une autre vue fait apparaître le titre, mais pas la vue. En d'autres termes, je me retrouve avec le titre de la vue n sur la pile, mais la vue affichée est toujours la vue n+1 (le résultat est que vous êtes piégé sur cet écran et ne pouvez pas revenir à la vue racine - vous pouvez aller dans l'autre sens, c'est-à-dire pousser plus de vues et revenir à la vue qui ne s'est pas affichée correctement, mais pas à la vue racine. La seule façon de s'en sortir est de quitter l'application). À d'autres moments, la même séquence de poussées et de projections sur les mêmes vues fonctionne bien.

Celui-là en particulier me rend fou. Je pense qu'il peut être lié au fait que la vue disparaît avant que la vue web ne soit chargée, c'est-à-dire que dans ce cas, je soupçonne qu'il peut gribouiller sur la mémoire et confondre la pile de vues. Ou bien, cela pourrait n'avoir aucun rapport et être un bogue ailleurs (je n'ai jamais été capable de le reproduire en mode de construction de débogage, cela ne se produit qu'avec les paramètres de construction de version lorsque je ne peux pas le regarder avec gdb :-). D'après mes tests de débogage, je ne pense pas que je libère trop de choses. Et je ne semble pouvoir le déclencher que si, à un moment donné, j'ai touché la vue qui contient la vue Web, et que cela ne se produit pas immédiatement après.

-1voto

abuharsky Points 467

Peut-être en rapport avec cela, il m'arrive (encore une fois totalement intermittent), je reçois un affreux heisenbug lorsque je clique sur le bouton sur la barre de navigation d'une autre vue fait apparaître le titre, mais pas la vue. En d'autres termes, je me retrouve avec le titre de la vue n sur la pile, mais la vue affichée est toujours la vue n+1. vue affichée est toujours la vue n+1 (le résultat est que vous êtes piégé sur cet écran et ne peut pas revenir à la vue racine vous pouvez aller dans l'autre direction, c.-à-d. pousser plus de vues et retourner à la la vue qui n'est pas apparue correctement, mais pas à la vue racine. La seule La seule façon de s'en sortir est de quitter l'application). A d'autres moments fois, la même séquence de poussées et de pops sur les mêmes vues fonctionne bien.

J'ai le même problème, lorsque j'utilise un contrôleur de navigation avec des contrôleurs de vue dans la pile > 2 et l'index du contrôleur de vue actuel > 2, si un memoryWarning se produit dans ce moment, cela pose les mêmes problèmes.

Il n'y a qu'une seule solution, que j'ai trouvée après de nombreuses expériences avec le remplacement des méthodes pop et push dans NavigationController, avec la pile de contrôleurs de vue, avec des vues et des supervisions pour les ViewControllers empilés, etc.

#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>

@interface FixedNavigationController : 
UINavigationController <UINavigationControllerDelegate>{

}

@end

#import "FixedNavigationController.h"

static BOOL bugDetected = NO;

@implementation FixedNavigationController

- (void)viewDidLoad{
    [self setDelegate:self];
}

- (void)didReceiveMemoryWarning{
    // FIX navigationController & memory warning bug
    if([self.viewControllers count] > 2)
        bugDetected = YES;
}

- (void)navigationController:(UINavigationController *)navigationController 
didShowViewController:(UIViewController *)viewController 
animated:(BOOL)animated
{

    // FIX navigationController & memory warning bug
    if(bugDetected){
        bugDetected = NO;

        if(viewController == [self.viewControllers objectAtIndex:1]){
            [self popToRootViewControllerAnimated:NO];
            self.viewControllers = [self.viewControllers arrayByAddingObject:viewController];
        }
    }
}

@end

Cela fonctionne bien pour 3 contrôleurs de vue en pile.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X