PALoadingView
Bonjour à tous,
Voici une vue permettant d'afficher une petite bulle d'attente.
Il y a plusieurs options comme l'affichage d'un voile derrière cette bulle, afin de montrer à l'utilisateur que l'action effectuée bloque l'interface pendant un petit moment (ça peut être utile dans un login par exemple).
Plusieurs possibilité de réglage aussi comme la durée des fade in/out (qui peuvent aussi être désactivés), etc..
Voici une vue permettant d'afficher une petite bulle d'attente.
Il y a plusieurs options comme l'affichage d'un voile derrière cette bulle, afin de montrer à l'utilisateur que l'action effectuée bloque l'interface pendant un petit moment (ça peut être utile dans un login par exemple).
Plusieurs possibilité de réglage aussi comme la durée des fade in/out (qui peuvent aussi être désactivés), etc..
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
Merci !
Bon je me suis pas foulé pour la présentation mais comme je vous l'ai dis, vous en faite ce que vous voulez. Moi je me suis fait ça justement parce que c'était ultra-simple à mettre en place
En effet je me mets dans mon app delegate et dans appdidfinishlaunching je commence à parser un xml retiré du web.
Je voudrais donc mettre le loader pendant que je parse.
J'ai fait :
Mais au lieu d'avoir un loader, j'ai toujours mon splashscreen qui se met pendant pas mal de temps (car le xml est assez lourd) dans mon loader par dessus. Il apparait juste 0,5 sec quand mon splashscreen disparait et que le parsage est terminé. Comment faire pour le faire apparaitre correctement?
Merci !
La meilleure méthode serait de faire le parsing dans un nouveau thread et de mettre self.activity à nil une fois fini, via une notification ou quelque chose du genre.
Mais je trouve ça bizarre que le parsing bloque ton appli... Normalement ça ne devrait pas. Donc je sais pas comment tu t'y prend.
En tout cas, à vue de nez, si le splashscreen dure le temps du parsing, c'est bien que ton [self parseXMLFileAtURL:path] bloque tout.
Et même si ça ne bloquait pas l'appli, tu ne verrais pas ton "activity" s'afficher vu que tu le mets à nil directement.
Et puis rien ne t'empêches d'envoyer une notification lorsque ton parsing est terminé (sans monopoliser ton main thread) afin d'instancier la viewController censée gérer l'affichage de ces données.
Pendant ce temps, tu auras juste la fenêtre de chargement.
Je l'ai rajouté dans tes classes et sous IB.
Dès qu'un element est parsé et donc créé j'incrémente une variable que je mets ensuite à ce label. Le truc c'est qu'il ne change pas le label comme si celui-ci était bloqué.
Et depuis que j'ai mis le loading dans un nouveau thread j'ai une tonne de messages sur la console (cf image)
Je comprends pas pourquoi
Passer son appli en multithreeading et créer des nouveaux threads nécessite un minimum de choses à savoir, la création d'une AutoReleasePool (chose que tu n'as manifestement pas fait), la protection des variables et la synchronisation (mutex, @synchrinize,...), les risques de deadlock, ...
Bref, faut pas se lancer dedans avant d'avoir lu le Programming Guide et suivre les pratiques obligatoires pour mettre en place un thread. C'est pas super compliqué mais ça nécessite de la rigueur et de comprendre les problématiques et risques (protection ressources partagées, update de l'UI dans mainthread, deadlock...) pour s'assurer qu'on les évite.
Par contre dans le programming guide je ne vois pas où ils indiquent comment changer un élément d'une UI .
Sinon tu as d'autres docs importantes à lire si tu commences le threading pour avoir conscience du LifeCycle de ton application, genre Application's Life Cycle : Do not block the main thread.
Mais de manière générale, il y a plein de trucs importants dans le Threading PG : comme je l'ai dit, créer un thread à la base c'est simple, mais il faut déjà être sûr que c'est bien la réponse à notre problématique (car cela a des conséquences), qu'un mécanisme existant, en particulier des méthodes asynchrones (avec utilisation de delegates pour les notifications et resynchronisations) comme il en existe un peu partout dans le framework Cocoa, n'est pas plus adapté... (pour le parsing XML t'as tout ce qu'il faut, créer un thread pour faire du parsing XML alors qu'on a un parseur XML asynchrone est de l'overhead et déconseillé pour moi), et regarder sinon s'il n'y a pas d'autres solutions plus adéquates (genre NSOperation, etc)
Là si tu n'as jamais fait de threads et vu les petits trucs qu'il va te falloir vérifier pour s'assurer que l'utilisation d'un thread ne risque pas de planter aléatoirement ton appli (par défaut de synchronisation ou accès concurrent à des ressources que tu n'aurais pas protégées par mutex, etc), alors que tu peux éviter tout ça et que NSXMLParser a tout ce qu'il faut pour faire du parsing asynchrone (parsing SAX événementiel)... tu risques de te compliquer la vie et introduire des risques dans ton appli avec les threads à mon avis.
ça aussi c'est expliqué dans le Threading PG.
Sinon j'ai pas suivi tout ton contexte, mais je vois pas trop le souci : le NSXMLParser sous iPhone (et il existe sous Mac aussi d'ailleurs) est de toute façon forcément un parsing SAX (donc événementiel, donc asynchrone). Cf la doc de NSXMLParser, et le PG assicié (Event-Driven XML PG).
Donc de toute façon normalement tu n'as pas le choix, quand tu fais du parsing XML sous iPhone, c'est du event-driven, donc c'est non bloquant, et grace au delegate que tu affectes au NSXMLParser, tu es notifié quand le parsing est terminé, etc...
Tu le tiens d'où ton parseXMLFileAtURL ? Car à priori c'est lui qui est bloquant.
Il faut que tu crées un NSXMLParser initialisé avec une URL, règle son delegate, puis demandé "parse" dessus. Après je suis sûr à 100% que le parsing est asynchrone, par contre la requête de récupération du fichier (pour récupérer le contenu de l'URL spécifiée) j'ai un doute tout à coup, je ne sais pas si dans ce cas c'est pas un download bloquant... mais bon ça m'étonnerait, normalement tout dans cette procédure est asynchrone.
Je pense que c'est correct car il me parse tout correctement. C'est après que j'ai décidé de me servir du travail d'Eagle pour faire une page de chargement afin que l'user ne s'inquiète pas du temps de chargement.
Et pour l'UI en faisant du perform ça marche, en fait j'affiche combien d'éléments j'ai parsé. D'ailleurs j'arrive pas à retirer tout au départ le nombre d'élément total que j'ai (pour pouvoir faire un pourcentage).
Comme je le disais plus haut, j'ai un doute, peut-être que la partie "téléchargement du XML se trouvant à l'URL spécifiée" est bloquante dans ce genre de cas, même si je crois que non, ça reste à vérifier. Mais le reste n'est pas bloquant, puisque justement c'est de l'event-driven.
Pour mieux comprendre le tout, tu peux mettre des traces dans ton parser:didStartDocument et parser:didEndDocument (voire même mieux, des breakpoints sonores qui vont faire un bip quand ça passe dans ces méthodes) pour comprendre la correspondance entre ces évènements (début du download du XML, fin du download et début du parsing, fin du parsing) et ce que tu as à l'écran (l'affichage de la vue du PALoadingController, mise à jour de l'interface, affichage de ton spashscreen, ...)
Si tu pouvais nous faire un mini diagramme de séquence (genre via websequencediagrams.com) entre ce qui est attendu, et ce que tu as réellement, qu'on comprenne bien l'enchaà®nement que tu as et la corrélation entre ce qui se passe sous le capot (parsing, etc) et ce que tu as à l'écran.
Si tu peux nous décrire du coup ce que tu obtiens à la place et donc exactement à quel moment interviennent les divers affichages en réalité à l'écran (PALoading qui s'affiche que juste avant la fin, etc...)
Voir avec Louka aussi bien sûr, j'ai pas du tout regardé comment sa classe PALoadingController était fichue :P
Ce qui est bloquant c'est la récupération du XML à mon avis. Enfin ça dépend, si t'es en edge oui ça peut mettre du temps
Mais :
C'est pas très cool. Pourquoi ne pas utiliser NSURLConnection?
Enfin, vu la taille du XML c'est pas bien grave Mais n'empêche que dans le cas où l'utilisateur est contraint d'utiliser le Edge, ça peut vite être bloquant pendant 30 bonnes secondes.
En revanche, depuis le simulateur, tu utilises la connexion du Mac.. donc si ça bloque via le simulateur c'est qu'il y a un problème effectivement.
Mais ça n'empêche pas qu'encore une fois, tu instancies le PALoadingController pour le mettre à nil directement après : utilité ?
Donc pour faire dans l'ordre, j'ai fais la trace de mes méthodes de parsing et voilà comment c'est appelé au lancement de l'application:
A la fin la méthode parseDidEndDocument est bien appelée.
Ensuite ton scénario est correct quand je mets le parsing dans un second thread . Sinon sans faire ça j'ai cet UML
Pour NSURLConnection faut que je regarde comment on s'en sert.
Quand je mets le loader à nil je le mets dans ma méthode parseDidEndDocument.
J'espere que c'est un peu plus clair
Aussi simple que ça d'utiliser NSURLConnection
Avec NSURLConnection plus besoin de thread, le loader se met super bien.
Par contre mon UILabel que j'ai rajouté ne veut pas se rafraichir pendant que je parse.
Avant je l'avais performer a cause du thread mais là normalement il n'y a plus besoin ...
Ah et aussi j'aimerai bien connaitre genre le nombre de balise <new> que j'ai dans mon XML avant de parser pour pouvoir faire 1/13 ; 2/13 ; etc .... Mais je vois pas comment faire
Enfin faut que je trouve pourquoi mon UILabel veut pas se rafraà®chir
Tu veux de bonnes infos essentielles ?
Enfin c'est mon avis et un conseil que je te donne, tu fais comme tu veux, mais disons qu'il faut aller à l'essentiel plutôt que de trop détailler. (Les détails comme ça, c'est un vilain défaut que j'avais à l'époque aussi, et je t'avoues que c'est pas user-friendly du tout).
Par contre, le méchant Aligator dis que ce n'est pas possible de compter le nombre de balises portant le nom "<new>", mais je suis un grand adepte du "cheat" :
Un peu la flemme de vérifier, mais je penses que tu devras sûrement faire un "newTagsCount--;"
Parfois c'est long car j'ai des images à télécharger mais je pense que mettre ça est mieux en effet
Par conte j'ai toujours le même soucis : ça ne rafraichi pas
Ce qui prend du temps c'est donc :
- Le téléchargement de ton XML (selon la vitesse de connexion, la rapidité de réponse du serveur qui l'héberge, la taille du XML)
- Le traitement que tu fais de tes données lors du parsing, par exemple si le code que tu mets dans didStartElement ou didEndElement est long
Si c'est le téléchargement qui prend du temps, tu peux éventuellement essayer de récupérer la taille attendue de tes données (nombre d'octets de ton XML quoi) au moment où tu reçois les headers HTTP (NSURLConnectionDelegate te retourne la NSURLResponse dans laquelle tu as les headers dont le Content-Length, enfin j'ai pas essayé mais ça parait logique).
Si c'est le traitement que tu fais dans ton parsing qui prend du temps, tu peux peut-être faire ton parsing en deux temps : d'abord un parsing rapide, qui se contente de faire le parsing événementiel de ton XML pour compter les tags <new> sans rien faire d'autre, et un deuxième parsing, le réel, qui traite tes données, construit ton arbre de données de ton modèle du MVC à partir du XML, etc.
Mais est-ce que ça en vaut vraiment la peine, à toi de voir.
Tu m'étonnes que ça soit long au démarrage ^^
Et comme ça l'utilisateur attend au lancement de l'appli même s'il veut juste vite fait consulter un truc parmi tout ce que tu charges...
"> Hop, poubelle :P