IPB

Bienvenue invité ( Connexion | Inscription )

 
Reply to this topicStart new topic
> Télécharger un fichier en tâche de fond [Résolu]
Options
Slumb
posté 23 Jul 2014, 14:38
Message #1


Macbidouilleur d'argent !
***

Groupe : Membres
Messages : 782
Inscrit : 11 Sep 2005
Membre no 45 692



Bonjour à tous,

Je travaille actuellement sur un proto qui est constitué d'une UIToolBar et juste en dessous d'une UIWebView. Je télécharge un fichier PDF et je l'affiche dans ma webview. Le problème c'est qu'au lancement de mon application j'ai l'écran qui reste noir plusieurs secondes et une fois le PDF téléchargé, tout s'affiche.

L'idée serait d'avoir l'App qui s'affiche en premier (c'est à dire la UIToolBar), ensuite le PDF une fois téléchargé. Entre les deux, une UIProgressionBar (ça c'est facile).

J'ai bien essayé de séparer le code qui charge le PDF dans une méthode, essayé les blocs mais dans les deux cas, le résultat est identique. C'est à dire que ni le PDF, ni la UIWebView ne s'affichent jamais.

Merci pour votre aide.

EDIT : tout le code se trouve dans mon initWithFrame, ce qui (a mon avi), n'est pas des plus "propres"...

EDIT2 : j'avais du oublier un truc, le code dans une méthode à part fonctionne mais toujours écran noir pendant quelques secondes au démarrage (je m'y attendais). Faut-il créer une classe à part ?

Ce message a été modifié par Slumb - 28 Jul 2014, 16:36.


--------------------
iMac 27" - MBP 15"
PC ASUS Z97 WIFI + Bluetooth - Intel Core i7-4790K CPU 4,00GHz - GeForce 980 GTX ZOTAC 4Go - 16Go RAM - SSD Crucial
Bluetooth Device (Personal Area Network)
Bluetooth Device (RFCOMM Protocol TDI)
Carte réseau Broadcom 802.11ac
Intel Ethernet Connection I218-V
Go to the top of the page
 
+Quote Post
ntx
posté 23 Jul 2014, 17:43
Message #2


Macbidouilleur d'Or !
*****

Groupe : Membres
Messages : 2 490
Inscrit : 19 Aug 2004
Lieu : 92
Membre no 22 254



Il faut faire le chargement dans un thread à part, par exemple en utilisant la classe NSOperation. Si tu veux une progression quantifiée, il faut connaître la taille du fichier et le thread de chargement doit régulièrement envoyer un message vers le thread principal pour mettre à jour la barre de progression.

Attention, à la fin du chargement exécute ton code pour mettre à jour ta vue principale dans le thread principal. Tout ce qui touche à l'IHM doit toujours se faire dans le thread principal.
Go to the top of the page
 
+Quote Post
Jaypee
posté 24 Jul 2014, 05:48
Message #3


Macbidouilleur d'Or !
*****

Groupe : Membres
Messages : 2 486
Inscrit : 29 Aug 2002
Membre no 3 340



Il y a des pistes ici : http://stackoverflow.com/questions/1820295...-in-objective-c qui cite cette lib sur GitHub: https://github.com/couchdeveloper/RXPromise

Les abstractions utilisées pour les tâches asynchrones dans d'autres langages sont "futur et promesse".
Pour protéger la tâche en cours on l'emballe dans une boîte appelée Futur. Lorsque qu'elle sera prête, elle se signalera. Et ce qu'on peut faire entrer séparément dans un Futur en cours de réalisation, c'est une promesse.
Cela permet de reprendre la main, après avoir décrit ce qui va se passer, sans avoir à attendre que le Futur ne se réalise complètement.

J-P

Ce message a été modifié par Jaypee - 24 Jul 2014, 06:26.
Go to the top of the page
 
+Quote Post
Slumb
posté 24 Jul 2014, 10:35
Message #4


Macbidouilleur d'argent !
***

Groupe : Membres
Messages : 782
Inscrit : 11 Sep 2005
Membre no 45 692



Bonjour et merci pour vos retours. Jaypee, je met ça de côté et je regarderais dès que possible de manière plus approfondi.

Je propose la solution suivante :

Code
NSURL *myURL = [NSURL URLWithString:@"https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSArray_Class/NSArray_Class.pdf"];
        
        NSURLRequest *urlRequest = [NSURLRequest requestWithURL:myURL];
        
        NSOperationQueue *queue = [[NSOperationQueue alloc] init];
        
        [NSURLConnection sendAsynchronousRequest:urlRequest queue:queue completionHandler:^(NSURLResponse *urlResponse, NSData *data, NSError *error) {
            NSLog(@"data.length : %lu", (unsigned long)data.length);
            if (data.length > 0 && error == nil) {
                [myWebView loadRequest:urlRequest];
                [self setNeedsDisplay];
                UIAlertView *alertOk= [[UIAlertView alloc] initWithTitle:@"Ok" message:@"Le fichier est chargé" delegate:self cancelButtonTitle:@"Ok" otherButtonTitles: nil];
                [alertOk show];
            }
            else if (data.length == 0 && error == nil) {
                UIAlertView *alertEmpty = [[UIAlertView alloc] initWithTitle:@"Attention" message:@"Le fichier est vide" delegate:self cancelButtonTitle:@"Ok" otherButtonTitles: nil];
                [alertEmpty show];
            }
            else if (error != nil) {
                UIAlertView *alertError = [[UIAlertView alloc] initWithTitle:@"Attention" message:@"Erreur de téléchargement" delegate:self cancelButtonTitle:@"Ok" otherButtonTitles: nil];
                [alertError show];
            }
            NSLog(@"%@", urlResponse);
        }];


Le alertOk va disparaitre, c'était juste pour tester. Donc ça fonctionne très bien car mon App s'affiche et quand le PDF est télécharger il apparait dans la UIWebView.

Dites moi ce que vous en pensez et peut-être que cela sera utile a d'autres. Pour information, j'ai trouvé cette solution hier dans le livre "CookBook Développement iOS 7 - 60 recettes de pros" aux éditions DUNOD. Pour le coup ce bouquin commence vraiment à ce rendre utile, je le conseille smile.gif

Je profite de poser une autre question, car j'ai eu le même type de problème sur les NSTextField. Dans la dernière ligne de code, j'ai ceci :

Code
NSLog(@"%@", urlResponse);


J'aimerais récupérer le statut de retour HTML. Quand je regarde la doc, j'ai ceci :

Citation
The related NSHTTPURLResponse class is a commonly used subclass of NSURLResponse whose objects represent a response to an HTTP URL load request and store additional protocol-specific information such as the response headers. Whenever you make an HTTP request, the NSURLResponse object you get back is actually an instance of the NSHTTPURLResponse class.


Mais je ne vois pas comment me débrouiller pour récupérer le statut qui est bien présent dans NSHTTPURLResponse.

Merci pour votre aide.

Ce message a été modifié par Slumb - 24 Jul 2014, 10:35.


--------------------
iMac 27" - MBP 15"
PC ASUS Z97 WIFI + Bluetooth - Intel Core i7-4790K CPU 4,00GHz - GeForce 980 GTX ZOTAC 4Go - 16Go RAM - SSD Crucial
Bluetooth Device (Personal Area Network)
Bluetooth Device (RFCOMM Protocol TDI)
Carte réseau Broadcom 802.11ac
Intel Ethernet Connection I218-V
Go to the top of the page
 
+Quote Post
Jaypee
posté 24 Jul 2014, 11:48
Message #5


Macbidouilleur d'Or !
*****

Groupe : Membres
Messages : 2 486
Inscrit : 29 Aug 2002
Membre no 3 340



Ici: http://stackoverflow.com/questions/8126056...httpurlresponse

Pour les autres infos, ce qui peut arriver c'est que le site soit protégé par une sécurité "basique", nom + mot de passe. La requête contiendra alors une en-tête spéçiale qui indique au client du protocole (HTTP, FTP...) d'afficher le dialogue de connexion.

JP
PS: la lib RxPromise gère aussi l'interruption, si on décide d'abandonner le téléchargement.
Go to the top of the page
 
+Quote Post
Slumb
posté 24 Jul 2014, 12:28
Message #6


Macbidouilleur d'argent !
***

Groupe : Membres
Messages : 782
Inscrit : 11 Sep 2005
Membre no 45 692



Bon j'ai au moins deux questions :

1 : J'ai regardé ton lien et je ne comprends pas ce qu'est (dans son exemple) le httpResponse ? J'ai essayé plusieurs trucs mais rien. Dans la doc, la méthode localizedStringForStatusCode existe bien mais elle prends en argument un NSInteger. A ce sujet quand j'affiche mon urlResponse j'ai ceci qui s'affiche dans le Terminal :

Code
<NSHTTPURLResponse: 0x9658a40> { URL: https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSArray_Class/NSArray_Class.pdf } { status code: 200, headers {
    "Accept-Ranges" = bytes;
    Connection = "Keep-Alive";
    "Content-Length" = 512574;
    "Content-Type" = "application/pdf";
    Date = "Thu, 24 Jul 2014 09:46:31 GMT";
    "Keep-Alive" = "timeout=15, max=313";
    "Last-Modified" = "Thu, 24 Jul 2014 01:15:03 GMT";
    Server = Apache;
    "X-Frame-Options" = "SAMEORIGIN, SAMEORIGIN";
} }


Le statut est bien présent.


2 : Mon code dans le post précédent est fonctionnel mais je n'avais pas vu une chose. J'ai besoin de connaitre le poids du fichier avant de le télécharger (est-ce possible ? si oui, comment ?) et d'ajouter une UIProgressBar qui évoluera donc en fonction des octets téléchargés. Problème, le completionHandler est appelé apparemment qu'une seule et une fois, a la fin (la UIProgressBar ne me pose pas de problème, juste où placer les appels de méthodes pour son évolution et la masquer a la fin du download).

Encore merci Jaypee.

EDIT : Est-ce une bonne idée d'utiliser les méthodes du protocole UIWebViewDelegate pour "surveiller" le téléchargement du fichier PDF, comme ici :

Code
- (void)webViewDidStartLoad:(UIWebView *)webView {
    NSLog(@"PDF start download");
}

- (void)webViewDidFinishLoad:(UIWebView *)webView {
    NSLog(@"PDF downloaded");
}


J'ai bien ce résultat :

Code
PDF start download
PDF downloaded


Par contre je n'ai toujours pas de méthode qui tourne en boucle pour le téléchargement en lui-même afin de faire progresser ma UIProgressBar.


EDIT 2 : Très mauvaise idée, et quid de NSURLConnection/NSURLSession ? (je suis en train de regarder la doc et faire quelques tests, si c'est pas bon je vais allez voir du côté des promises).

Ce message a été modifié par Slumb - 24 Jul 2014, 17:01.


--------------------
iMac 27" - MBP 15"
PC ASUS Z97 WIFI + Bluetooth - Intel Core i7-4790K CPU 4,00GHz - GeForce 980 GTX ZOTAC 4Go - 16Go RAM - SSD Crucial
Bluetooth Device (Personal Area Network)
Bluetooth Device (RFCOMM Protocol TDI)
Carte réseau Broadcom 802.11ac
Intel Ethernet Connection I218-V
Go to the top of the page
 
+Quote Post
Slumb
posté 24 Jul 2014, 21:53
Message #7


Macbidouilleur d'argent !
***

Groupe : Membres
Messages : 782
Inscrit : 11 Sep 2005
Membre no 45 692



Jaypee, quel intérêt d'utiliser RXPromise ? (je suis un peu englué dans la doc là, un peu d'aide serais very helpful smile.gif )

Ce message a été modifié par Slumb - 25 Jul 2014, 22:40.


--------------------
iMac 27" - MBP 15"
PC ASUS Z97 WIFI + Bluetooth - Intel Core i7-4790K CPU 4,00GHz - GeForce 980 GTX ZOTAC 4Go - 16Go RAM - SSD Crucial
Bluetooth Device (Personal Area Network)
Bluetooth Device (RFCOMM Protocol TDI)
Carte réseau Broadcom 802.11ac
Intel Ethernet Connection I218-V
Go to the top of the page
 
+Quote Post
Jaypee
posté 25 Jul 2014, 06:31
Message #8


Macbidouilleur d'Or !
*****

Groupe : Membres
Messages : 2 486
Inscrit : 29 Aug 2002
Membre no 3 340



RxPromise est UNE implémentation d'une proposition Promise/A+ un certain design pour traiter les opérations asynchrones.

Si on ne fait pas un design soigné, on part pour une téléchargement de PDF et on se trouve avec une exception due à un certificat manquant ou un encodage inconnu, bref à essayer de comprendre un résultat qui n'a rien à voir avec le problème initial.

Il se trouve qu'il en existe une autre en ObjC, https://github.com/MSNexploder/SHXPromise dont un exemple commence par une requête web, donc tu t'y retrouveras sans doute mieux.

Lis aussi le Wikipédia sur Futur et Promesse, cette page de blog http://sametmax.com/deferred-future-et-pro...-ce-quon-mange/

Il y un exemple très simple: calculer (factorielle 1_000_000_000) + 1
Factorielle d'un aussi gros nombre va prendre un certain temps, on crée alors un Futur dans lequel il y a une Promesse que la factorielle est calculée, et une autre Promesse qu'on lui ajoutera 1 quand ce sera prêt.
On a immédiatement un statut du style: OK, Futur créé, et on continue à faire autre chose, le Futur va se signaler quand il sera réalisé.

JP

Ce message a été modifié par Jaypee - 25 Jul 2014, 18:47.
Go to the top of the page
 
+Quote Post
Slumb
posté 25 Jul 2014, 22:44
Message #9


Macbidouilleur d'argent !
***

Groupe : Membres
Messages : 782
Inscrit : 11 Sep 2005
Membre no 45 692



"Si on ne fait pas un design soigné, on part pour une téléchargement de PDF et on se trouve avec une exception due à un certificat manquant ou un encodage inconnu, bref à essayer de comprendre un résultat qui n'a rien à voir avec le problème initial."

Par certificat, tu veux dire si on télécharge sur du https, par exemple ? Qu'il faut vérifier les données téléchargés ?


Une petite question au passage... Quand on veut ouvrir un fichier dans une UIWebView, est-il possible de tester si cette UIWebView est capable de lire et donc d'ouvrir ce fichier ? dataDetectorTypes ne retourne pas de boolean et je ne vois rien d'autres.


--------------------
iMac 27" - MBP 15"
PC ASUS Z97 WIFI + Bluetooth - Intel Core i7-4790K CPU 4,00GHz - GeForce 980 GTX ZOTAC 4Go - 16Go RAM - SSD Crucial
Bluetooth Device (Personal Area Network)
Bluetooth Device (RFCOMM Protocol TDI)
Carte réseau Broadcom 802.11ac
Intel Ethernet Connection I218-V
Go to the top of the page
 
+Quote Post
Jaypee
posté 26 Jul 2014, 06:48
Message #10


Macbidouilleur d'Or !
*****

Groupe : Membres
Messages : 2 486
Inscrit : 29 Aug 2002
Membre no 3 340



Les différentes couches de code qu'on doit appliquer pour obtenir un résultat, comportent chacune des possibilités d'erreur (d' exceptions)
Donc si on ne canalise pas bien toutes ces erreurs, elles remontent à la surface comme des bulles d'une boisson pétillante. Et c'est ainsi qu'on peut recevoir des exceptiosn de couches qu'on ne souhaite même pas connaître.

Ce sont des problèmes complexes, donc la solution peut être complexe, mais il faut prendre le temps de l'apprendre.

Je ne suis pas expert en Cocoa, je ne pourrai pas t'aider sur l'autre question.

JP
Go to the top of the page
 
+Quote Post
Slumb
posté 26 Jul 2014, 08:13
Message #11


Macbidouilleur d'argent !
***

Groupe : Membres
Messages : 782
Inscrit : 11 Sep 2005
Membre no 45 692



Ok, je pense avoir compris, merci pour ton aide.


--------------------
iMac 27" - MBP 15"
PC ASUS Z97 WIFI + Bluetooth - Intel Core i7-4790K CPU 4,00GHz - GeForce 980 GTX ZOTAC 4Go - 16Go RAM - SSD Crucial
Bluetooth Device (Personal Area Network)
Bluetooth Device (RFCOMM Protocol TDI)
Carte réseau Broadcom 802.11ac
Intel Ethernet Connection I218-V
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 utilisateur(s) sur ce sujet (1 invité(s) et 0 utilisateur(s) anonyme(s))
0 membre(s) :

 



Nous sommes le : 20th April 2024 - 01:42