2010-05-31 4 views
1

J'ai créé une vue de grille qui affiche six "cellules" de contenu. Dans chaque cellule, une image est chargée à partir du Web. Il y a plusieurs pages de cette grille (l'utilisateur les parcourt en faisant défiler vers le haut/le bas pour voir l'ensemble de cellules suivant). Chaque cellule possède son propre contrôleur de vue. Lorsque ces contrôleurs de vue se chargent, ils utilisent une classe ImageLoader que j'ai créée pour charger et afficher une image. Ces contrôleurs de vue implémentent un ImageLoaderDelegate qui a une méthode unique qui est appelée lorsque l'image est terminée de chargement. ImageLoader fait son travail sur un thread d'arrière-plan, puis notifie simplement son délégué lorsque le chargement est terminé, en passant l'image à la méthode déléguée.Problème de chargement de l'image d'arrière-plan du SDK de l'iPhone

Problème: si l'utilisateur passe à la page suivante du contenu de la grille avant la fin du chargement de l'image (en libérant les GridCellViewControllers qui utilisent ImageLoaders), l'application se bloque. Je suppose que c'est parce que le long de la ligne, une méthode asynchrone se termine et tente d'informer son délégué, mais ne peut pas parce qu'il a été libéré.

est ici un code pour donner une meilleure image:

GridCellViewController.m:

- (void)viewDidLoad { 
    [super viewDidLoad]; 

    // ImageLoader 
    _loader = [[ProductImageLoader alloc] init]; 
    _loader.delegate = self; 

    if(_boundObject) 
     [_loader loadImageForProduct:_boundObject]; 
} 

//ImageLoaderDelegate method 
- (void) imageDidFinishLoading: (UIImage *)image { 
    [_imgController setImage:image]; 
} 

ProductImageLoader.m

- (void) loadImageForProduct: (Product *) product { 
    // Get image on another thread 
    [NSThread detachNewThreadSelector:@selector(getImageForProductInBackground:) toTarget:self withObject:product]; 
} 

- (void) getImageForProductInBackground: (Product *) product { 
    NSAutoreleasePool *tempPool = [[NSAutoreleasePool alloc] init]; 

    HttpRequestLoader *tempLoader = [[HttpRequestLoader alloc] init]; 

    NSURL *tempUrl = [product getImageUrl]; 

    NSData *imageData = tempUrl ? [tempLoader loadSynchronousDataFromAddress:[tempUrl absoluteString]] : nil; 

    UIImage *image = [[UIImage alloc] initWithData:imageData]; 

    [tempPool release]; 

    if(delegate) 
     [delegate imageDidFinishLoading:image]; 
} 

L'application se bloque avec EXC_BAD_ACCESS. Clause de non-responsabilité: Le code a été légèrement modifié pour se concentrer sur le problème en question.

Répondre

1

La moitié du temps je pose une question ici, je viens avec une solution peu de temps après. Ecrire le problème est probablement 90% de la solution.

Quoi qu'il en soit, voici ce que j'ai fait, et il y a probablement une amélioration à apporter à cela car je me méfie encore des discussions. Il s'est avéré que le problème était que la méthode déléguée se déclencherait toujours (imageDidFinishLoading), mais que le délégué avait été libéré. En définissant explicitement le délégué à zéro dans GridCellViewController.m lorsqu'il est libéré, le message ne se déclenche jamais.

GridCellViewController.m

- (void) dealloc { 
    if(_loader) { 
     _loader.delegate = nil; 
     [_loader release]; 
    } 
} 
+0

Ceci est la bonne approche. Si vous vous définissez comme délégué sur un objet, vous devez ignorer ce délégué lorsque vous êtes libéré. –

+0

Super, merci. J'apprends quelque chose de nouveau tous les jours. –

+0

Consultez cet article de Jeff Lamarche: http://iphonedevelopment.blogspot.com/2010/05/downloading-images-for-table-without.html si vous avez encore des doutes sur l'utilisation des threads, ne les utilisez pas . Et votre application sera mieux pour cela;) – Jasarien