[Résolu] Memory Pressure

MagiicMagiic Membre
octobre 2014 modifié dans API UIKit #1

Salut,


 


Je viens vers vous car je suis face à  un problème qui me désoriente un peu. Dans le cadre d'une application, une partie importante repose sur l'affichage de nombreuses photos (500) intégrées dans le projet. Rien que les photos emportaient un poids de plus de 1,2G. J'ai compressé le tout et j'arrive finalement à  un poids total avec me code source de 70M.


J'explique ceci car cela peut vous aider à  mieux comprendre mon problème.


 


Un menu de mon application sur iPad consiste à  afficher des images en catégories/sous catégories à  l'aide d'une collectionView.


Les images (leurs noms) sont stockés dans une base de donnée gérée par CoreData. 


Lors de l'affichage des cellules j'utilise la méthode suivante pour afficher l'image dans une imageView incorporée à  l'aide du storyboard dans ma cellule.



cell.picture.image = [UIImage imageNamed:realisation.file];

Et c'est ici que la mémoire utilisée s'emballe. Lorsque le collectionView s'affiche, ma mémoire utilisée passe de 20M à  110M. Je reçois plein d'alertes en ce sens à  chaque fois. Finalement, après plusieurs aller retour l'application finit par crasher avec comme seule indication : Message from debugger: Terminated due to Memory Pressure. Si je n'utilise pas la ligne ci-dessus et que donc je n'affiche rien tout, cela fonctionne sans accroc. La récupération des donnée avec CoreData n'engendre pas une mémoire significative.


 


Je pense (c'est sur) que je dois mal m'y prendre pour l'affichage des images mais malheureusement je ne vois pas où. Je dois faire des erreurs quelques part et je compte sur vous pour m'aiguiller.


 


Voici des extraits de mon code.


 


Ici pour afficher les images dans le collectionView



-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
TMCollectionCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@Cell forIndexPath:indexPath];

// Récupérer la réalisation et l'afficher.
Realisation *realisation = [_realisationsItems objectAtIndex:indexPath.row];
cell.picture.image = [UIImage imageNamed:realisation.file];

// Permettre d'envoyer la photo par email avec un long toucher.
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(sendRealisation:)];
longPress.minimumPressDuration = 1.0;
[cell addGestureRecognizer:longPress];

return cell;
}


Ici, une méthode qui me permet de récupérer toutes les images liées à  la sous catégorie souhaitée



+(NSArray *)allRealisationsBySubCategory:(SubCategoryMavip *)subCategory {
NSManagedObjectContext *context = [self context];

NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:REALISATION];

NSPredicate *predicate = [NSPredicate predicateWithFormat:@(subReal.name = %@)", subCategory.name];
[request setPredicate:predicate];

NSError *error;
NSArray *allRealisations = [context executeFetchRequest:request error:&error];

if (allRealisations.count > 0) {
return allRealisations;
} else {
NSLog(@Aucune Réalisation en base de donnée\n);
return @[;];
}
}

Mots clés:

Réponses

  • Si ma mémoire est bonne, "imageNamed" ne libère jamais la mémoire utilisée par l'image, qui reste tout le temps en mémoire (afin qu'un nouvel appel à  la méthode avec le même nom de fichier soit plus rapide).

    Il faut clairement passer par une autre méthode lorsqu'on doit gérer un grand nombre d'images qui ne sont pas toutes visibles en même temps (genre "imageWithContentOfFile").
  • MagiicMagiic Membre
    octobre 2014 modifié #3

    J'ai pas testé imageWithContentsOfFile. Dans la documentation, ils disent que imageNamed permet de mettre en cache l'image tandis que la première est plus intéressante si on ne la charge qu'une fois. Mais c'est une bonne idée. Je teste et j'édite.


     


    Edit :


     


    ça ne change pas grand chose malheureusement. Toujours la même chose, une fois arrivé au collectionView je passe de 20M à  120M. Pourtant le nombre de cellule affichée reste minimes. Entre 20 et 60 maxi. Chaque cellule n'embarque qu'une imageView et un Label.


  • AliGatorAliGator Membre, Modérateur
    Je t'invite fortement à  lire ceci : http://nshipster.com/image-resizing/

    En particulier, si tes images sont si lourdes (très grosses résolutions, etc), il ne faut afficher que des miniatures dans ta CollectionView. Quand je dis miniatures, c'est pas charger la UIImage HD puis l'afficher dans une UIImageView avec un mode "AspectFit" qui va l'afficher plus petite, c'est vraiment ne charger que la représentation miniature des données de l'image, pour ne pas charger en mémoire les données binaires de la représentation HD

    Et pour faire cela, tu as plusieurs techniques un peu + avancées que de directement taper dans "[UIImage imageNamed:]". Dont ImageIO en particulier, qui va éviter de lire l'image HD sur le disque tout ça pour n'afficher que la miniature mais directement réduire l'impact mémoire sans s'embêter à  décoder toute l'image HD en mémoire pour rien.
  • Ok. Je lis ça et je reviens vers vous si j'ai des questions. Merci.


  • Salut,


     


    Merci beaucoup pour le lien. C'était exactement ça mon problème. Je remarque quand même que la qualité diminue sensiblement par rapport à  celle d'origine mais reste correct.


    Toutefois j'ai encore une question à  ce sujet. J'embarque un slider pour afficher chaque image en sizeToFit sur l'ensemble de l'écran d'un iPad. Je ne peux pas utiliser les méthodes citées sinon la qualité d'affichage devient affreuse, je dois les garder en origine seulement la mémoire consommée augmente sensiblement.


     


    Il y a un moyen de solutionner ce problème ?


  • Finalement, après avoir change d'iPad pour passer d'un mini à  un 3 j'ai remarqué que la mémoire utilisée était très stable, 25M environ dans toute mon application. L'utilisation de l'api imageIO a bien marché et à  réduit très nettement la consommation de mémoire avec un bémol cependant c'est en diminuant la qualité.


    Merci pour votre aide.


Connectez-vous ou Inscrivez-vous pour répondre.