UITableView Rapide

jojolebgjojolebg Membre
avril 2012 modifié dans API UIKit #1
Bonjour,



je viens vers vous car j'ai un problème d'optimisation sur ma TableView.

Je suis actuellement sur un projet ou je doit afficher une tableview dont chaque cellule contiendra une image (de la taille de l'écran iPhone).

Ce sont des images JPEG qui font entre 600 et 800ko.

Dans une tableview il peux y avoir plus de 130 cellules.



Je ne sais pas trop comment m'y prendre pour que la tableview soit réactive.

Actuellement j'ai essayé deux méthodes.

La première, celle que j'utilise d'habitude, donne de très mauvais résultat. Elle ressemble à  ça:


<br />
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath<br />
{<br />
	static NSString *CellIdentifier = @&quot;Cell&quot;;<br />
	UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];<br />
  <br />
	if (cell == nil) {<br />
		cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault<br />
									  reuseIdentifier:CellIdentifier];<br />
		UIImageView *imageView = [[[UIImageView alloc] initWithFrame:CGRectMake(0,0,<br />
																				320,<br />
																				537)] autorelease];<br />
		imageView.tag = 770;<br />
		[cell.contentView addSubview:imageView];<br />
		[cell autorelease];<br />
	}<br />
  <br />
	NSString *stringImage = @&quot;07.0&quot;;<br />
	stringImage = [stringImage stringByAppendingFormat:@&quot;%d.jpg&quot;, indexPath.row];<br />
	UIImageView *imageView = (UIImageView *)[cell.contentView viewWithTag:770];  <br />
	imageView.image = nil;<br />
  <br />
	objc_setAssociatedObject(cell, kIndexPathAssociationKey, indexPath, OBJC_ASSOCIATION_RETAIN);<br />
	dispatch_async(dispatch_get_main_queue(), ^{<br />
		NSIndexPath *oldIndexPath = objc_getAssociatedObject(cell, kIndexPathAssociationKey);<br />
		if ([oldIndexPath isEqual:indexPath]) {<br />
			imageView.image = [UIImage imageNamed:stringImage];<br />
		}<br />
	});<br />
	return cell;<br />
}<br />




Avec cette première méthode, j'utilise un chargement asynchrone des images. J'associe à  chaque cellule l'indexpath courant. Pour que dans le block asynchrone je puisse vérifié si le chargement de l'image est toujours d'actualité (si la cellule n'a pas changé d'image).



Le defilement de la tableview est trop saccadé (quand on veut allé vite sur la tableview).

J'ai donc pensé à  un système que je n'arrive pas à  mettre en place.
  • On charge l'image, seulement si la cellule est visible depuis x ms. Avec x un nombre assez petit pour ne pas voir la saccade, mais assez grand pour faire en sorte que la tableview soit réactive.


J'en arrive à  ce code.


<br />
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath<br />
{<br />
	static NSString *CellIdentifier = @&quot;Cell&quot;;<br />
	UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];<br />
  <br />
	if (cell == nil) {<br />
		cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault<br />
									  reuseIdentifier:CellIdentifier];<br />
		UIImageView *imageView = [[[UIImageView alloc] initWithFrame:CGRectMake(0,0,<br />
																				320,<br />
																				537)] autorelease];<br />
		imageView.tag = 770;<br />
		[cell.contentView addSubview:imageView];<br />
		[cell autorelease];<br />
	}<br />
  <br />
	NSString *stringImage = @&quot;07.0&quot;;<br />
	stringImage = [stringImage stringByAppendingFormat:@&quot;%d.jpg&quot;, indexPath.row];<br />
	UIImageView *imageView = (UIImageView *)[cell.contentView viewWithTag:770];  <br />
	imageView.image = nil;<br />
  <br />
	NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:<br />
							  cell, @&quot;cell&quot;,<br />
							  indexPath, @&quot;indexPath&quot;,<br />
							  imageView, @&quot;imageView&quot;,<br />
							  stringImage, @&quot;stringImage&quot;,<br />
							  nil];<br />
  <br />
	objc_setAssociatedObject(cell, kIndexPathAssociationKey, indexPath, OBJC_ASSOCIATION_RETAIN);<br />
<br />
	float xxx = 0.500 /// Le xxx est ici<br />
	[NSTimer scheduledTimerWithTimeInterval:xxx<br />
									 target:self selector:@selector(loadImage:) userInfo:userInfo repeats:false];<br />
	return cell;<br />
}<br />
- (void)loadImage:(NSTimer *)timer<br />
{<br />
	NSDictionary *userInfo = timer.userInfo;<br />
	UIImageView *imageView = [userInfo objectForKey:@&quot;imageView&quot;];<br />
	NSIndexPath *indexPath = [userInfo objectForKey:@&quot;indexPath&quot;];<br />
	NSString *stringImage = [userInfo objectForKey:@&quot;stringImage&quot;];<br />
	UITableViewCell *cell = [userInfo objectForKey:@&quot;cell&quot;];<br />
<br />
<br />
	dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0ul);<br />
	dispatch_async(queue, ^{<br />
		dispatch_async(dispatch_get_main_queue(), ^{<br />
			NSIndexPath *oldIndexPath = objc_getAssociatedObject(cell, kIndexPathAssociationKey);<br />
			if ([oldIndexPath isEqual:indexPath]) {<br />
				imageView.image = [UIImage imageNamed:stringImage];<br />
			}<br />
		});<br />
	});<br />
}<br />




Avec cette technique la tableview est vraiment très réactive. Mais je n'arrive pas exactement à  ce que je voulais, car le xxx n'est jamais pris en compte, l'image se recharge seulement quand la tableview arrete de bougé. C'est à  dire que pendant le scroll, l'image ne se charge pas, mais elle se charge quand la tableview arrive à  la fin de son scroll.

Ce qui est assez genant.



Une idée pour accélérer ma tableview ?

En améliorant ma deuxième technique ou quelque chose de complètement different ?
«1

Réponses

  • JegnuXJegnuX Membre
    avril 2012 modifié #2
    Bon prou commencer, tu dis que tes images font la taille de l'ecran de l'iPhone, mais est-ce que les cellules elles mêmes font cette tailles ?



    L'idée serait de redimensionner par le code tes images pour qu'elles fassent la taille de ton imageView.

    Cette opération ne serait à  faire qu'une fois au premier chargement de ton image et après tu la stocke en cache dans un mutableDictionary (que tu peux vider dans le didReceiveMemoryWarning).



    Ensuite, je ne suis vraiment pas convaincu de ton utilisation de Grand Central Dispatch dans ton second exemple où tu fais un dispatch dans une queue à  part pour après refaire de suite le dispatch dans la main queue.



    ça marche pas de faire directement le dispatch sur la main queue ? En tout cas tu peux faire le redimensionnement de l'image dans ce block.



    Après, ça joue ptet pas énormément sur les perfs, mais à  quoi te sert ton associatedObject ? j'ai l'impression que c'est juste pour t'assurer que c'est bien la bonne cell que tu modifie et qu'elle n'ait pas été reuse entre temps.

    Mais pour ça tu as la methode cellForRowAtIndexPath: de ta tableView qui te retournera toujours la bonne cell (et nil si t'as row n'est pas visible il me semble).



    Enfin, tu devrais passer par une sous-classes de UITableViewCell, ce sera plus pratique que de passer par les tags et des dictionnaires.



    Si je résume, perso je ferais un truc du genre
    <br />
    // CustomCell.h <br />
    <br />
    @interface CustomCell : UITableViewCell<br />
    @property (nonatomic, retain) UIImageView *imageView;<br />
    @end<br />
    <br />
    // TonTableViewController.m<br />
    <br />
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath<br />
    {<br />
    	static NSString *CellIdentifier = @&quot;Cell&quot;;<br />
    	CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];<br />
    <br />
    	if (cell == nil) {<br />
    		cell = [[[CustomCell alloc] initWithReuseIdentifier:CellIdentifier] autorelease];<br />
    	}<br />
    <br />
    	NSString *stringImage = [NSString stringWithFormat:@&quot;07.0%d.jpg&quot;, indexPath.row];<br />
    	cell.imageView.image = nil;<br />
    <br />
    	dispatch_async(dispatch_get_main_queue(), ^{<br />
    		UIImage *image = [self.cachedImages objectForKey:stringImage];<br />
    		if (&#33;image) {<br />
    			image = [[UIImage imageNamed:stringImage] resizedImageWithSize:CGSizeMake(32.,48.)]; //ça existe pas comme méthode de base. Trouve toi une category ou code là  <img src='http://forum.cocoacafe.fr/public/style_emoticons/<#EMO_DIR#>/wink.png' class='bbc_emoticon' alt=';)' /><br />
    			[self.cachedImages setObject:image forKey:stringImage];<br />
    		}<br />
    		CustomCell *aCell = [tableView cellForRowAtIndexPath:indexPath];<br />
    		if (aCell) {<br />
    			aCell.imageView.image = resizedImage;<br />
    		}<br />
    	});<br />
    <br />
    	return cell;<br />
    }<br />
    
  • jojolebgjojolebg Membre
    avril 2012 modifié #3
    Bonjour JegnuX, merci de prendre la peine de m'aider à  trouver une solution.


    Bon prou commencer, tu dis que tes images font la taille de l'ecran de l'iPhone, mais est-ce que les cellules elles mêmes font cette tailles ?


    Je me suis mal exprimer, c'est la cellule qui fait la taille de l'écran, les images sont encore plus grandes (elles ont la resolution d'un ipad)


    L'idée serait de redimensionner par le code tes images pour qu'elles fassent la taille de ton imageView.

    Cette opération ne serait à  faire qu'une fois au premier chargement de ton image et après tu la stocke en cache dans un mutableDictionary (que tu peux vider dans le didReceiveMemoryWarning).


    Je vais essayé de suite et je te dit ce que ça donne. Mais j'ai peu que le redimensionnement prenne du temps, et que ça ne change pas le problème de fluidité.

    En faite la tableview peut contenir jusqu'à  150 cellules, et les cellules sont en général afficher qu'une seule fois. Soit en scrollant au fur et à  mésure, soit en passant directement à  la cellule X via des boutons prévu à  cet effets.


    Ensuite, je ne suis vraiment pas convaincu de ton utilisation de Grand Central Dispatch dans ton second exemple où tu fais un dispatch dans une queue à  part pour après refaire de suite le dispatch dans la main queue.



    ça marche pas de faire directement le dispatch sur la main queue ? En tout cas tu peux faire le redimensionnement de l'image dans ce block.


    Moi non plus je ne suis pas convaincu. A vrai dire, j'ai un peu joué avec tout ce que je pouvais pour arrivé à  un résultat correct. Quand je ne met qu'un seul dispatch sur une queue autre que la main queue, la cellule ne se réaffiche pas (je pense que c'est normal, car les modification de l'ui doit être fait seulement sur le main queue).



    Quand je met directement la dispatch sur la main queue, le résultat est identique c'est à  dire, l'image est afficher seulement quand la tableview est immobile.


    Après, ça joue ptet pas énormément sur les perfs, mais à  quoi te sert ton associatedObject ? j'ai l'impression que c'est juste pour t'assurer que c'est bien la bonne cell que tu modifie et qu'elle n'ait pas été reuse entre temps.

    Mais pour ça tu as la methode cellForRowAtIndexPath: de ta tableView qui te retournera toujours la bonne cell (et nil si t'as row n'est pas visible il me semble).


    Oui c'est pour m'assurer que la cell n'a pas été reuse entre temps. Je ne connaissais pas spécialement la méthode cellForRowAtIndexPath. Mais pour le associatedObject, j'avais lu sur un article que c'étais une bonne méthode.

    http://blog.slauncha...ble-view-cells/




    Enfin, tu devrais passer par une sous-classes de UITableViewCell, ce sera plus pratique que de passer par les tags et des dictionnaires.


    Cela va de soit, mais le code que j'ai donnée, et plus un prototype technique pour m'assurer que je pars dans la bonne direction.



    Cordialement.
  • KubernanKubernan Membre
    avril 2012 modifié #4
    À priori tes images sont des ressources de ton application.



    Je pense, qu'avant de faire de l'asynchrone, tu devrais d'abord optimiser l'affichage de ces images en (comme l'a suggéré Jegnux) sous classant ta cell.

    Tu peux par exemple réduire le blending des view de ta cell ce qui peut nettement améliorer les performances.

    Ce n'est qu'après que tu pourras introduire éventuellement de l'asynchrone si tu vois que les choses ne s'améliorent pas.
  • JegnuXJegnuX Membre
    avril 2012 modifié #5
    J'ai lu vite fait le lien que tu donnes et j'ai pas vu de associatedObjects...



    Par contre j'ai compris pourquoi il faisait un premier dispatch dans une queue à  part, puis un autre dans la main.

    Sauf que toi, tu fais pas comme lui et du coup tu perds l'avantage qu'il mentionne : l'ouverture du fichier en background. Alors que toi tu fais ton imageNamed: dans le block qui est appelé sur la main.



    Pour le redimensionnement et le cache c'est comme tu veux. Mais le cache en tout cas te permettrais de pas avoir a ré-ouvrir le fichier à  chaque passage sur ta cell.

    Voici le code que je t'avais donné un peu modifié. Tente le image/wink.png' class='bbc_emoticon' alt=';)' />
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath<br />
    {<br />
        static NSString *CellIdentifier = @&quot;Cell&quot;;<br />
        CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];<br />
        if (cell == nil) {<br />
            cell = [[[CustomCell alloc] initWithReuseIdentifier:CellIdentifier] autorelease];<br />
        }<br />
        NSString *stringImage = [NSString stringWithFormat:@&quot;07.0%d.jpg&quot;, indexPath.row];<br />
        cell.imageView.image = nil;<br />
    <br />
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);<br />
        dispatch_async(queue, ^{<br />
            UIImage *image = [self.cachedImages objectForKey:stringImage];<br />
            if (&#33;image) {<br />
                image = [UIImage imageNamed:stringImage];<br />
                [self.cachedImages setObject:image forKey:stringImage];<br />
            }<br />
            dispatch_async(dispatch_get_main_queue(), ^{<br />
                CustomCell *aCell = [tableView cellForRowAtIndexPath:indexPath];<br />
                if (aCell) {<br />
                    aCell.imageView.image = image;<br />
                }<br />
            });<br />
        });<br />
        return cell;<br />
    }<br />
    
  • 'Kubernan' a écrit:


    À priori tes images sont des ressources de ton application.



    Je pense, qu'avant de faire de l'asynchrone, tu devrais d'abord optimiser l'affichage de ces images en (comme l'a suggéré Jegnux) sous classant ta cell.

    Tu peux par exemple réduire le blending des view de ta cell ce qui peut nettement améliorer les performances.

    Ce n'est qu'après que tu pourras introduire éventuellement de l'asynchrone si tu vois que les choses ne s'améliore pas.




    D'accord, je passe tout de suite à  une sous classe.

    Je veux bien optimier l'affichage des images (c'est meme pour ça que je suis la). Mais je ne sais pas trop comment faire.

    Mais qu'est ce le blending des view de ma cell ?
  • J'ai lu vite fait le lien que tu donnes et j'ai pas vu de associatedObjects...


    [font=helvetica, arial, sans-serif]Il est dans le depot github donner en lien à  la fin de l'article.[/font]

    https://github.com/SlaunchaMan/GCDExample/blob/master/GCDExample/RootViewController.m#L139




    [font=helvetica, arial, sans-serif]Par contre j'ai compris pourquoi il faisait un premier dispatch dans une queue à  part, puis un autre dans la main.[/font]



    [font=helvetica, arial, sans-serif]Sauf que toi, tu fais pas comme lui et du coup tu perds l'avantage qu'il mentionne : l'ouverture du fichier en background. Alors que toi tu fais ton imageNamed: dans le block qui est appelé sur la main.[/font]


    [font=helvetica, arial, sans-serif]Je viens aussi de comprendre le truc.[/font]


    [font=helvetica, arial, sans-serif]Voici le code que je t'avais donné un peu modifié. Tente le [/font] image/wink.png' class='bbc_emoticon' alt=';)' />


    [font=helvetica, arial, sans-serif]J'essaye de suite et je vous tiens au courant.[/font]
  • 'jojolebg' a écrit:


    [font=helvetica, arial, sans-serif]Il est dans le depot github donner en lien à  la fin de l'article.[/font]

    https://github.com/S...ntroller.m#L139




    Ah exact. Mais je suis pas plus convaincu de sa pertinence par rapport à  l'utilisation de -cellForRowAtIndexPath:



    Ils en pensent quoi les autres ?
  • Avec ton code de jegnuX c'est pareil, la tableview est vraiment saccadé.
  • Quand tu dis que c'est saccadé, c'est l'ui qui se fige pendant le scroll ? comme si ça accrochait ?



    Qu'est ce qu'elle fait d'autre ton application ? Car la dans le code que j'ai mis, en théorie y'a pas grand chose qui bloque le main thread, donc ça devrait scroller sans accoups. Mais tu fais peut-être autre chose dans ton code qui bloque le main thread ?
  • Pour le moment mon application c'est juste ce code et rien d'autre. C'est seulement un prototype pour tester la faisabilité de la chose.

    Pour répondre à  la question: c'est pendant le scroll que sa saccade. En effet ça peut rester plus d'une seconde bloqué sur la meme cellule.

    Je pense que c'est cette ligne qui bloque le main thread
    [color=#000000][font=monospace][size=3]aCell[/size][/font][/color][color=#666600][font=monospace][size=3].[/size][/font][/color][color=#000000][font=monospace][size=3]imageView[/size][/font][/color][color=#666600][font=monospace][size=3].[/size][/font][/color][color=#000000][font=monospace][size=3]image [/size][/font][/color][color=#666600][font=monospace][size=3]=[/size][/font][/color][color=#000000][font=monospace][size=3] image[/size][/font][/color][color=#666600][font=monospace][size=3];[/size][/font][/color]
    




    Et ça devrait rejoindre ce que disait Kubernan en disant d'optimiser d'abord l'affichage des images. Car mes images font en moyenne 800ko, c'est surement l'affichage de l'image qui met du temps.
  • 'jojolebg' a écrit:


    Avec ton code de jegnuX c'est pareil, la tableview est vraiment saccadé.




    Synchrone ou pas... ton image il faut de toute façon l'afficher. Ca prend... un certain temps :-)

    Lorsque tu veux afficher une image le système graphique effectue pas mal d'opérations, notamment s'il y a nécessité de "mélanger" le rendu de certaines parties.



    Tu peux réduire ces calculs en utilisant par exemple des vues opaques (c.f. propriété opaque de UIView : If set to YES, the drawing system treats the view as fully opaque, which allows the drawing system to optimize some drawing operations and improve performance).



    Vérifie également la propriété Alpha de tes images. Si tu as la possibilité de la supprimer je crois que ça peut avoir un impact.



    Tu peux aussi aplatir la hiérarchie de tes vues. C'est ce que je fais pour certaines de mes cells qui affichent pas mal d'image : plutôt que de multiplier les UIImageView, je dessine (via drawRect:) toutes mes images dans une seule vue par la méthode drawAtPoint: de UIImage.
  • C'est pour un lecteur de BD, ou un système similaire ?
  • [font=helvetica, arial, sans-serif]



    Synchrone ou pas... ton image il faut de toute façon l'afficher. Ca prend... un certain temps :-)

    Lorsque tu veux afficher une image le système graphique effectue pas mal d'opérations, notamment s'il y a nécessité de "mélanger" le rendu de certaines parties.


    J'imagine bien que ça doit prendre un temps incompressible pour pouvoir afficher les images. Mais mon idée était d'afficher ces images seulement si il y a necessité, et cet necessité était définie par un temps d'affichage de la cellule. (chose que je n'arrive pas à  mettre en place).

    Mais normalement c'est juste des images simple. pas de mélange.


    Tu peux réduire ces calculs en utilisant par exemple des vues opaques (c.f. propriété opaque de UIView : If set to YES, the drawing system treats the view as fully opaque, which allows the drawing system to optimize some drawing operations and improve performance).


    J'ai passé le opaque de ma cellule ainsi que de mon uiimageview à  false. La difference se voit, mais sa reste encore beaucoup trop saccadé.


    Vérifie également la propriété Alpha de tes images. Si tu as la possibilité de la supprimer je crois que ça peut avoir un impact.


    Mes images sont des images jpg donc elle non pas de couches alpha.




    Tu peux aussi aplatir la hiérarchie de tes vues. C'est ce que je fais pour certaines de mes cells qui affichent pas mal d'image : plutôt que de multiplier les UIImageView, je dessine (via drawRect:) toutes mes images dans une seule vue par la méthode drawAtPoint: de UIImage.


    J'imagine que ça ne se fait pas facilement avec une UITableView ?




    C'est pour un lecteur de BD, ou un système similaire ?


    Le client possède un livre qu'il veut mettre sur iphone/ipad. Mais il ne possède qu'une version imagé de son livre.

    Donc c'est pour un lecteur de livre.[/font]
  • KubernanKubernan Membre
    avril 2012 modifié #15
    'jojolebg' a écrit:




    [font=helvetica, arial, sans-serif]J'imagine que ça ne se fait pas facilement avec une UITableView ?[/font]






    C'est pas compliqué du tout, je te conseille d'aller étudier l'exemple de code intitulé "AdvancedTableViewCells" dans les sample code Apple où tu as quelques exemples d'utilisation de sous classes de cell (dont un avec le drawAtPoint: dont je t'ai parlé).



    Il n'y a pas de solutions définitives soit dit en passant, il est parfois plus utile de laisser UIImageView faire. Il faut que tu regardes avec Instrument à  quel moment précis ton code consume le plus de temps.
  • DrakenDraken Membre
    avril 2012 modifié #16
    'jojolebg' a écrit:


    [font=helvetica, arial, sans-serif]Le client possède un livre qu'il veut mettre sur iphone/ipad. Mais il ne possède qu'une version imagé de son livre.

    Donc c'est pour un lecteur de livre.
    [/font]




    130 images de 800 Ko ça fait 101 Mo ! C'est beaucoup, vraiment beaucoup.. Vous avez pensé à  utiliser une solution d'OCR pour transformer les images en texte, du moins en partie ?



    Pense à  regarder la session 104 des vidéos Apple de la WWDC 2010, sur le site de développement. On y explique comment réaliser le système de scrolling de l'application Photo.
  • Le plus grand chapitre fait 130 images. En tout y'a plus de 250 images ce qui fait environ 200mo.

    On ne peux pas faire une solution d'OCR car la mise en page du texte est très importantes.
  • Un livre de 200 Mo ! image/crazy.gif' class='bbc_emoticon' alt=' B) ' />

    Pour être utilisable un ouvrage doit être adapté au format de lecture, pas simplement porté d'un support à  un autre.
  • Le livre n'est pas un livre de lecture, c'est un livre de prière.

    La mise en page de ce livre est ce qui fait sa spécificité, et les utilisateurs iPhone/iPad veulent retrouver la même mise en page que le support papier.

    La seul contrainte c'est la contrainte de poids, l'application pèse assez lourd, mais je ne vois pas comment faire autrement. Mais le faite qu'elle ressemble à  la version papier est voulu.
  • Tu n'aurais pas quelques images d'exemples à  montrer ? Il y a peut-être moyen de mixer du texte/OCR et du graphisme,si la mise en page le permet. Cela pourrais faire gagner une place mémoire considérable, et augmenter considérablement la fluidité de l'affichage.
  • Si c'est pour un livre, dans ce cas je comprend pas bien l'utilisations d'une tableview.



    Le mieux serait de faire une liseuse normale non ? C'est à  dire comme l'application photos : scroll horizontal uniquement (où vertical si tu y tiens vraiment, c'est possible aussi) et on ne charge que les images en n-1,n et n+1. Pas de scroll rapide mais juste un scroll de page en page.



    Ainsi on peut aussi optimiser la mémoire bien release les images qui ne sont pas en n-1,n et n+1 (à  ce sujet, n'utilise pas imageNamed: du coup car il met l'image en cache, mais c'est pas forcément utile ici donc fait avec initWithContentsOfFile: )



    Fin bref, du coup je pense pas que la tableView soit vraiment adapter à  ce que tu veux.
  • DrakenDraken Membre
    avril 2012 modifié #23
    Je ne vois pas de graphismes sur cette image, juste des caractères latins et des caractères hébreux, avec une présentation assez simple. Télécharge l'application gratuite Fonts sur l'AppStore. Tu verras que iOS possède de base des polices de caractères pour afficher de l'hébreu.



    En affichant tout sous forme de textes, tu passeras de 200 mo à  un ou deux Mo seulement ! Une paille, quoi .. Sans parler d'une colossale amélioration de la fluidité ! Et tu profiteras de la qualité d'affichage du Retina Display, sans rien modifier au code !
  • jojolebgjojolebg Membre
    avril 2012 modifié #24
    @jegnuX

    Justement c'est pour cela que j'utilise la tableview. Pour profiter des reuseCell sans avoir à  le recoder. A partir du moment ou j'utilise un défilement vertical (à  la demande du client), je trouve la tableview adaptée pour ne pas tout réinventer. Vu que ce n'est pas un livre de lecture, il faut pouvoir naviguer rapidement au scroll sur les differentes pages pour recherche le passage qui nous interesse.



    @Draken

    http://dl.dropbox.co...001_recadre.jpg

    Regarde à  ce niveau là  de l'image par exemple. Je ne vois pas comment représenté cette suite de mot en texte pure. Ni comment représenter une lettre qui en contient plusieurs (la quatrième lettre en partant de la droite contient un mot complet). Et à  la fin de la ligne il y a des mots qui sont écrit sur plusieurs ligne.

    Je suis d'accord, c'est sur que sa serait mieux d'avoir tout en vectoriel, ou d'avoir le texte brut. Mais c'est quelque chose que je n'est pas, et je ne sais pas comment représenté exactement la meme mise en page en utilisant un OCR
  • jojolebgjojolebg Membre
    avril 2012 modifié #25
    [color=#000000][font=monospace][size=3] dispatch_queue_t queue [/size][/font][/color][color=#666600][font=monospace][size=3]=[/size][/font][/color][color=#000000][font=monospace][size=3] dispatch_get_global_queue[/size][/font][/color][color=#666600][font=monospace][size=3]([/size][/font][/color][color=#000000][font=monospace][size=3]DISPATCH_QUEUE_PRIORITY_HIGH[/size][/font][/color][color=#666600][font=monospace][size=3],[/size][/font][/color][color=#006666][font=monospace][size=3]0ul[/size][/font][/color][color=#666600][font=monospace][size=3]);[/size][/font][/color]<br />
    [color=#000000][font=monospace][size=3]	dispatch_async[/size][/font][/color][color=#666600][font=monospace][size=3]([/size][/font][/color][color=#000000][font=monospace][size=3]queue[/size][/font][/color][color=#666600][font=monospace][size=3],[/size][/font][/color][color=#666600][font=monospace][size=3]^{[/size][/font][/color]<br />
    [color=#660066][font=monospace][size=3]UIImage[/size][/font][/color][color=#666600][font=monospace][size=3]*[/size][/font][/color][color=#000000][font=monospace][size=3]image [/size][/font][/color][color=#666600][font=monospace][size=3]=[/size][/font][/color][color=#666600][font=monospace][size=3][[/size][/font][/color][color=#000088][font=monospace][size=3]self[/size][/font][/color][color=#666600][font=monospace][size=3].[/size][/font][/color][color=#000000][font=monospace][size=3]cachedImages objectForKey[/size][/font][/color][color=#666600][font=monospace][size=3]:[/size][/font][/color][color=#000000][font=monospace][size=3]stringImage[/size][/font][/color][color=#666600][font=monospace][size=3]];[/size][/font][/color]<br />
    [color=#000088][font=monospace][size=3]if[/size][/font][/color][color=#666600][font=monospace][size=3](&#33;[/size][/font][/color][color=#000000][font=monospace][size=3]image[/size][/font][/color][color=#666600][font=monospace][size=3])[/size][/font][/color][color=#666600][font=monospace][size=3]{[/size][/font][/color]<br />
    [color=#000000][font=monospace][size=3]			image [/size][/font][/color][color=#666600][font=monospace][size=3]=[/size][/font][/color][color=#666600][font=monospace][size=3][[/size][/font][/color][color=#660066][font=monospace][size=3]UIImage[/size][/font][/color][color=#000000][font=monospace][size=3] imageNamed[/size][/font][/color][color=#666600][font=monospace][size=3]:[/size][/font][/color][color=#000000][font=monospace][size=3]stringImage[/size][/font][/color][color=#666600][font=monospace][size=3]];[/size][/font][/color]<br />
    [color=#666600][font=monospace][size=3][[/size][/font][/color][color=#000088][font=monospace][size=3]self[/size][/font][/color][color=#666600][font=monospace][size=3].[/size][/font][/color][color=#000000][font=monospace][size=3]cachedImages setObject[/size][/font][/color][color=#666600][font=monospace][size=3]:[/size][/font][/color][color=#000000][font=monospace][size=3]image forKey[/size][/font][/color][color=#666600][font=monospace][size=3]:[/size][/font][/color][color=#000000][font=monospace][size=3]stringImage[/size][/font][/color][color=#666600][font=monospace][size=3]];[/size][/font][/color]<br />
    [color=#666600][font=monospace][size=3]}[/size][/font][/color]<br />
    [color=#000000][font=monospace][size=3]		dispatch_async[/size][/font][/color][color=#666600][font=monospace][size=3]([/size][/font][/color][color=#000000][font=monospace][size=3]dispatch_get_main_queue[/size][/font][/color][color=#666600][font=monospace][size=3](),[/size][/font][/color][color=#666600][font=monospace][size=3]^{[/size][/font][/color]<br />
    [color=#660066][font=monospace][size=3]CustomCell[/size][/font][/color][color=#666600][font=monospace][size=3]*[/size][/font][/color][color=#000000][font=monospace][size=3]aCell [/size][/font][/color][color=#666600][font=monospace][size=3]=[/size][/font][/color][color=#666600][font=monospace][size=3][[/size][/font][/color][color=#000000][font=monospace][size=3]tableView cellForRowAtIndexPath[/size][/font][/color][color=#666600][font=monospace][size=3]:[/size][/font][/color][color=#000000][font=monospace][size=3]indexPath[/size][/font][/color][color=#666600][font=monospace][size=3]];[/size][/font][/color]<br />
    [color=#000088][font=monospace][size=3]if[/size][/font][/color][color=#666600][font=monospace][size=3]([/size][/font][/color][color=#000000][font=monospace][size=3]aCell[/size][/font][/color][color=#666600][font=monospace][size=3])[/size][/font][/color][color=#666600][font=monospace][size=3]{[/size][/font][/color]<br />
    [color=#000000][font=monospace][size=3]				aCell[/size][/font][/color][color=#666600][font=monospace][size=3].[/size][/font][/color][color=#000000][font=monospace][size=3]imageView[/size][/font][/color][color=#666600][font=monospace][size=3].[/size][/font][/color][color=#000000][font=monospace][size=3]image [/size][/font][/color][color=#666600][font=monospace][size=3]=[/size][/font][/color][color=#000000][font=monospace][size=3] image[/size][/font][/color][color=#666600][font=monospace][size=3];[/size][/font][/color]<br />
    [color=#666600][font=monospace][size=3]}[/size][/font][/color]<br />
    [color=#666600][font=monospace][size=3]});[/size][/font][/color]<br />
    [color=#666600][font=monospace][size=3]});[/size][/font][/color]<br />
    [color=#000088][font=monospace][size=3]return[/size][/font][/color][color=#000000][font=monospace][size=3] cell[/size][/font][/color][color=#666600][font=monospace][size=3];[/size][/font][/color]
    







    [font=helvetica, arial, sans-serif]Ah exact. Mais je suis pas plus convaincu de sa pertinence par rapport à  l'utilisation de -cellForRowAtIndexPath:[/font]

    [font=helvetica, arial, sans-serif]Ils en pensent quoi les autres ?[/font]




    Je viens de tomber sur un cas ou l'utilisation de cellForRowAtIndexPath ne marche pas dans l'utilisation que l'on fait.

    En effet parfois on rentre à  l'interieur du dispatch_async avant meme de faire le return cell,(donc dès fois c'est synchrone)

    Et à  l'interieur du dispatch_async on appel la méthode cellForRowAtIndexPath qui va forcement renvoyé nil car le return Cell n'a pas été fait. Pour l'instant chez moi ce cas n'arrive qu'a la première cellule de la tableview, et qu'au premier chargement.

    Il y a surement un moyen de ruser. Mais les deux cas ne sont pas directement interchangeable.
  • Cette lettre qui en contient plusieurs est probablement une ponctuation particulière à  l'hébreu. Si c'est le cas, ça doit être intégré d'une manière ou d'une autre à  l'unicode. Tu dois pouvoir trouver des infos sur le sujet sur le net, ou chercher quelqu'un connaissant le sujet.



    A priori ton ouvrage est un ouvrage religieux traditionnel. Il en existe peut être des versions libres de droits sous forme numérique. Cela pourrais t'aider de les étudier.
  • Nan ce n'est pas un signe de ponctuation particulier à  l'hébreu, meme si il est vrai que ce mot en particulier se retrouve dans beaucoup d'ouvrage hebreu.

    http://dl.dropbox.com/u/9704388/forum/07.053.jpg

    De plus je ne vois pas comment rendre ce genre de page facilement. Avec traduction mot à  mot.



    Je le répète, je suis entièrement d'accord avec toi Draken. Mais sa me demanderait un gros travail de refaire un siddour entièrement. (ce genre de livre de prière s'appelle un siddour). Et ce n'est pas dans le cadre de ce projet.
  • AliGatorAliGator Membre, Modérateur
    Si tu tiens vraiment à  faire le rendu d'images, tu n'as pas le choix : il te faut des images LowDef



    Ce qui prend le plus de temps c'est surtout de lire le fichier image, et le charger en RAM. L'affichage prend également du temps, bien qu'un peu moins.

    Si tu veux pouvoir défiler rapidement, il faut que dans ton cellForRowAtIndexPath tu affectes une image en basse définition, lue depuis un fichier image bien moins lourd donc bien moins long à  charger. Ou préchargée dans un tableau de UIImage que tu gardes de côté, bien que ça ferait garder quasi tout le livre (même si tu le remplis au fur et à  mesure) en RAM et donc risquerait là  aussi de faire beaucoup.

    Et quand la scrollView décélère (tu as une méthode de delegate qui te prévient de ça) voire s'arrête de scroller, tu charges l'image High Def à  la place de l'image LowDev (utilise la propriété visibleCells de UITableView pour ça)



    Bref dans tous les cas il te faudra faire des compromis : tes images sont grosses donc longues à  charger, tu ne peux pas les charger en un temps records pour fluidifier ton scrolling. Et tu ne peux pas toutes les précharger ne mémoire, car elles sont trop grosses et ça exploserait la RAM. Donc il faut que tu embarques dans ton bundle des versions basse définition de tes images* en plus des images HD.



    * note que si tes images sont toutes comme celles que tu as montrée plus haut, donc que du texte mais en plus qu'en noir et blanc ou niveau de gris, il y a certainement moyen d'optimiser la taille même en gardant des images sans parler d'OCR...?
  • DrakenDraken Membre
    avril 2012 modifié #29
    Il y a une autre approche, convertir les pages en png monochrome au lieu du jpg. C'est jouable dans la mesure où le document original est entièrement en noir et blanc. Avec un essai rapide, la page de ton exemple passe de 410 Ko en jpg à  106 Ko en png 2 couleurs. J'ai utilisé GIMP pour convertir le format.



    EDIT : Grilled par Ali, comme toujours !
  • Merci pour tout vos conseils,

    Je vais commencé par faire un traitement par lot. Et utilisé la technique des photo lowres de Aligator voir ce que ça donne.
  • Je n'ai pas Gimp installer sur mon poste, mais je n'arrive pas à  reproduire Draken.

    J'ai essayé pas mal de reglages avec photoshop mais je n'arrive pas à  avoir des images plus legère que la version jpg.
Connectez-vous ou Inscrivez-vous pour répondre.