Charger plusieurs images dans un scrollView et plantage

yodarkyodark Membre
00:15 modifié dans API UIKit #1
Bonjour à  tous,

J'ai un petit problème. Je voudrais charger des miniatures d'images dans un scrollView comme dans l'application Photos quand on a l'aperçu de toutes les photos.

Ca passe parfaitement sur le simulateur mais le device ne supporte pas que charge plus d'une dizaines d'images. Si j'en charge plus l'application plante simplement.

Comment faire pour afficher ces images sans que cela soit trop lourd pour l'application ?

Mes images originales sont assez grande elle font 330x465

NSBundle * mainBundle=[NSBundle mainBundle];<br />	<br />	if ([[reponseArray objectAtIndex:0] isEqualToString:@&quot;COLLECTION BOX&quot;])<br />	{<br />		for (int i = 0 ; i &lt; [reponseArray count]; i++)<br />		{<br />			<br />			for (int col = 0 ; col &lt;= 4; col++)<br />			{<br />				<br />				UIImage * myImage = [[[UIImage alloc] initWithContentsOfFile: [mainBundle pathForResource:@&quot;202&quot; ofType:@&quot;png&quot;]] retain ];<br />				UIImageView * imgCard = [[[UIImageView alloc] init] retain ];<br />				[imgCard setImage:myImage];<br />				[myImage release];<br />				<br />				<br />				<br />				CGRect frame = scrollView.frame;<br />				frame.origin.x = (77 + 5) * col + 5 ;<br />				frame.origin.y = (103 + 5) * i + 5;<br />				frame.size.height = 103 ;<br />				frame.size.width = 77 ;<br />				imgCard.frame = frame;<br />				[scrollView addSubview:imgCard];<br />				[imgCard release];<br />			}<br />			<br />			<br />		}<br />	}<br />



Réponses

  • allianallian Membre
    00:15 modifié #2
    Ton code à  l'air pas mal à  première vue, je suis pas sur mais essaye cela :

    <br />UIImageView *imgCard = [UIImageView alloc] init];<br />imgCard.image = [UIImage imageNamed:@&quot;202.png&quot;];<br />...<br />[scrollView addSubview:imgCard];<br />[imgCard release];
    
  • mai 2009 modifié #3
    Effectivement c'est un problème de mémoire. Je hais l'iPhone pour ça.
    Allian a tort. Il ne faut surtout pas utiliser +imageNamed: pour ce genre de vue. Le +imageNamed: comme l'indique la doc, met les images en cache. Ducoup que tu fasses un retain/release dessus ou pas, l'image reste en mémoire dans l'application pour se charger rapidement au prochain appel.
    Donc il faudra utiliser plutôt -initWithContentsOfFile: en utilisant NSBundle pour obtenir le chemin de l'image.
    Je rajouterai même que pour gagner en fluidité, il faudra effectuer ça dans un nouveau thread et ne charger que les images visible à  l'écran.

    Donc ton code est juste. Le seul problème c'est que tu fais un retain sur l'image...
    il faut que tu saches qu'à  partir du moment où tu utilise "init", il y a déjà  un retain effectué sur l'objet.
    Ainsi voilà  comment devrait être ton code pour éviter le plantage :

    <br />NSBundle * mainBundle=[NSBundle mainBundle];<br />	<br />	if ([[reponseArray objectAtIndex:0] isEqualToString:@&quot;COLLECTION BOX&quot;])<br />	{<br />		for (int i = 0 ; i &lt; [reponseArray count]; i++)<br />		{<br />			<br />			for (int col = 0 ; col &lt;= 4; col++)<br />			{<br />				<br />				UIImage * myImage = [[UIImage alloc] initWithContentsOfFile: [mainBundle pathForResource:@&quot;202&quot; ofType:@&quot;png&quot;] ];<br />				UIImageView * imgCard = [[UIImageView alloc] init ];<br />				[imgCard setImage:myImage];<br />				[myImage release];<br />				<br />				<br />				<br />				CGRect frame = scrollView.frame;<br />				frame.origin.x = (77 + 5) * col + 5 ;<br />				frame.origin.y = (103 + 5) * i + 5;<br />				frame.size.height = 103 ;<br />				frame.size.width = 77 ;<br />				imgCard.frame = frame;<br />				[scrollView addSubview:imgCard];<br />				[imgCard release];<br />			}<br />			<br />			<br />		}<br />	}<br />
    


    Faut vraiment faire gaffe à  ce genre de chose. Non seulement tu as retenu l'image et l'imageView 2 fois, mais en plus tu les a relaché qu'une seule fois. Donc soit tu met 2 release pour l'image et 2 release pour l'imageView, soit tu retires ces retain inutiles et tu laisses le release image et release imageView
  • allianallian Membre
    00:15 modifié #4
    Merci de m'avoir corrigé j'ai essayé de l'aider avec mes faibles compétences, du coup j'aurais appris quelque chose, je ne savais pas que imageNamed faisait un retain merci je vais faire quelques modifs dans mes app :D
  • 00:15 modifié #5
    dans 1243002311:

    Merci de m'avoir corrigé j'ai essayé de l'aider avec mes faibles compétences, du coup j'aurais appris quelque chose, je ne savais pas que imageNamed faisait un retain merci je vais faire quelques modifs dans mes app :D


    imageNamed ne fait pas vraiment un retain.. enfin on peut le voir comme ça effectivement, mais il ne faut pas croire qu'il faut faire un release après un imageNamed hein! Surtout pas!
    Non c'est juste que sur iPhone il faut éviter d'utiliser imageNamed: pour tout ce qui est manipulation de photos. Après si vous devez utiliser ça pour faire des controls personnalisés ça pose aucun problème.
  • allianallian Membre
    00:15 modifié #6
    Du coup pour mon code je sais pas trop si je dois garder ce que je faisait avant ou si je modifie vu que mes images se chargent toutes les 0.12s.
    C'est pour simuler un mouvement.
    Je fais ça :

    self.view = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@&quot;eni4.png&quot;]];
    
  • 00:15 modifié #7
    dans 1243003378:

    Du coup pour mon code je sais pas trop si je dois garder ce que je faisait avant ou si je modifie vu que mes images se chargent toutes les 0.12s.
    C'est pour simuler un mouvement.
    Je fais ça :

    self.view = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@&quot;eni4.png&quot;]];
    



    ça dépend de l'image! Et combien tu en a, vu que je vois un "4".. si ça va de 1 à  10 par exemple.. 10 images de 2Ko c'est rien du tout. Je crois que l'iPhone a 128Mo de RAM.. (je crois).
  • yodarkyodark Membre
    00:15 modifié #8
    Ok ca marche mieux mais ca plante quand même si j'ai beacoup d'images

    Pour le scrolling tu parlais d'un thread

    - (void)scrollViewDidScroll:(UIScrollView *)sender {
    


    J'imagine que tu parles de ce delegate. Mais a partir de la je suis un peu perdu. Comment charger progressivement les images si il y en a 200 par exemple. Dois je removeFromSuperview les autres ?
  • allianallian Membre
    00:15 modifié #9
    En faite j'en est 4 * 5 images et elles font 4ko chacune mais je pense que c'est mieux que je fasse imageNamed vu que j'ai 4 instances qui utilisent ces memes images et vu que c'est assez rapide leur chargement, ce sont des méchants dans pacman, ça doit etre mieux. Enfin je crois.
    ::)
  • 00:15 modifié #10
    dans 1243005713:

    Ok ca marche mieux mais ca plante quand même si j'ai beacoup d'images

    Pour le scrolling tu parlais d'un thread

    - (void)scrollViewDidScroll:(UIScrollView *)sender {
    


    J'imagine que tu parles de ce delegate. Mais a partir de la je suis un peu perdu. Comment charger progressivement les images si il y en a 200 par exemple. Dois je removeFromSuperview les autres ?


    Ce n'est pas un thread mais un delegate ça.
    Par contre oui sert toi de ce delegate pour faire un thread.. mais si tu n'as jamais vu les thread je te conseille de continuer comme ça meme si c'est lent. l'optimisation tu la fera plus tard.

    Donc les images à  charger, il faut que tu charges en premier ce qui est visible.
    Si tu comptes des carré de 48*48, il faut que tu t'arranges pour calculer combien d'images sont visibles à  l'écran dès le lancement.. c'est des maths pas trop compliquées quoi.
    Ensuite faut absolument que tu fasses un système de NSArray, comme ça tu te retrouveras mieux.
    Lorsque l'utilisateur scroll, il tu reçois "scrollViewDidScroll:", dans cette méthode tu re-calcule les images visibles (leurs index en vérité grâce), et là  tu récupères leur path grâce aux index + la NSArray. Il ne faudra pas oublier effectivement de retirer les images. qui ont disparu de l'écran (enfin qui ne sont plus visibles par l'utilisateur).

    J'ai eu à  faire le meme genre de truc.. et comme c'était des photos qui ne bougeront pas du tout de l'application (c'est à  dire que l'utilisateur n'en rajoutera pas), j'ai fait un programme sur Mac qui se charge de générer une image qui contient toutes les miniatures. à  partir de là  je calcule l'index de l'image que l'utilisateur selectionne grâce aux méthodes de touch. Là  au moins ça plantait pas vu que c'est une seule image de 320 de largeur et X hauteur.
    Donc si t'es dans le meme cas que moi et que l'utilisateur n'a pas à  rajouter des images, je peux te filer le générateur de miniatures.
Connectez-vous ou Inscrivez-vous pour répondre.