récupérer une page html.

tabliertablier Membre
septembre 2014 modifié dans Langages Web & serveurs #1

J'ai cet appel à  envoyer à  un site:



http://XX.aconit.org/XXX_X/xxxx.php?db=XX&action=identification&user=XXXX&access=XXXXX&nrinv=XXXX



 xxxx.php extrait des informations d'une base de données et renvoie une page très simplifiée que je veux récupérer dans un string! 


J'ai essayé ce que j'ai trouvé sur stackoverflow:



- (NSArray*)getObjectsFromWeb 


{


    NSURL *url = [NSURL URLWithString:@l-appel-ci-dessus];


    NSStringEncoding usedEncoding;


    NSError *error;


    NSString *data = [NSString stringWithContentsOfURL:url


                                          usedEncoding:&usedEncoding


                                                 error:&error];


 


    return [data componentsSeparatedByString:@<\b>];


}



ça ne marche pas mais je n'ai pas d'erreur!


Si j'écris l'appel directement dans Safari, j'obtiens bien le bon retour!


Ou est-ce que je me plante ?


Réponses

  • AliGatorAliGator Membre, Modérateur
    septembre 2014 modifié #2
    Ca veut dire quoi "ça marche pas" ?

    La requête n'est pas envoyée? La réponse te retourne un code d'erreur (error != nil) ? data est nil ? Les deux ?

    Sinon utiliser "stringWithContentsOfURL" est une très mauvaise idée / pratique. Car cela fait du synchrone, autrement dit ton application va rester bloquée (l'utilisateur va sans doute penser qu'elle est gelée et qu'elle a plantée) pendant tout le temps où la requête est effectuée et attend la réponse. Sur un device mobile, ça peut être catastrophique vu qu'on n'a pas toujours une bonne connectivité (en Edge les requêtes peuvent être longues) ; Sur un ordinateur de bureau c'est moins fréquent, mais ça peut arriver quand même (connexion ADSL loin du DSLAM,ou alors tu as un gros download (genre Xcode6 :P) en arrière plan qui te prend toute ta bande passante, etc). Dans tous les cas, il ne faut jamais bloquer le mainThread et donc l'interface utilisateur, en terme d'UX c'est plutôt rédhibitoire.

    Utilise plutôt NSURLConnection ou NSURLSession (cf le "URL Loading System Programming Guide" pour + d'infos) et jamais ni les dataWithContentsOfURL ou stringWithContentsOfURL, ni même le sendSynchronousRequest, car tout ça est synchrone et bloquant.
  • tabliertablier Membre
    septembre 2014 modifié #3

    Je ne peux pas répondre à  tout, je vais retourner voir.


    Le download est court. Sous Safari, le retour est instantané. La seule chose que j'ai dans le string data c'est "\n\n\n".


    Et le compte est chez OVH.  Je vais regarder ce que tu m'as indiqué. Je me suis planté sur le <\b> que je vais mettre à  <br/>, mais je ne crois pas que ce soit ça le problème.


     


    voici un retour typique (j'ai supprimé 2 URL à  L'intérieur):



    OK<br/>Machine<br/>Galvanomètre<br/>AOIP<br/>2<br/>732<br/>jpg<br/>44335<br/>733<br/>jpg<br/>jpg_0/733.jpg<br/>41814<br/>



  •   ???   Il faut toujours reconnaitre ses erreurs ou bêtises: En fait, la méthode citée en haut du post fonctionne!


    J'ai récupérer l'URL dans le source d'une page html que mon fils m'a envoyée. Oui, Mais tous les & du texte original sont devenus &amp; en HTML, ce qui donne une certaine confusion et l'URL est refusé par le serveur bien sur! 


     


    @ muqqadar


    A noter ma réponse précédente dont la citation dépasse allègrement le cadre !!!


  • AliGatorAliGator Membre, Modérateur
    Ok. Ce qui n'empêche pas qu'utiliser [NSString stringWithContentsOfURL:] est une très mauvaise idée.

    Même si sur ton mac le chargement semble rapide, si la personne qui veut utiliser ton application est par exemple dans le train en train d'utiliser son iPhone en mode modem pour espérer avoir un peu de réseau, ça va pas être follichon la connexion réseau et du coup ça va faire geler ton application.

    C'est d'ailleurs le genre de trucs qui se passe parfois avec Word, qui cherche à  vérifier je ne sais quoi sur le réseau (je pense qu'il vérifie si la licence d'utilisation est bonne ou un truc comme ça) et tout à  coup tout gèle car manque de pot tu n'as pas de réseau et ils ont codé ça comme les pieds et du coup tu perds toutes tes données (c'est du vécu).

    Sans parler du fait que ta méthode s'appelle "getObjectsFromWeb" ce qui est un très mauvais nommage qui ne respecte pas les conventions de nommage Apple (sémantiquement, les méthodes commençant par "get" passent par référence l'objet dans lequel écrire les données, comme les méthodes "getBytes:count:" & co. Ce qui n'est pas le cas ici)


    C'est vraiment pas compliqué de convertir ça en asynchrone, avec par exemple :
    - (void)fetchObjectsFromWebWithCompletion:( void(^)(NSArray*) )completion
    {
    NSURL *url = [NSURL URLWithString:@l-appel-ci-dessus];
    NSURLRequest* request = [NSURLRequest requestWithURL:url];
    [NSURLConnection sendAsynchronousRequest:request
    queue:[NSOperationQueue mainQueue]
    completionHandler:^(NSURLResponse* r, NSData* data, NSError* e)
    {
    NSString* string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    NSArray* lines = [string componentsSeparatedByString:@<br/>];
    completion(lines);
    }];
    }


    // Utilisation :
    [self fetchObjectsFromWebWithCompletion:^(NSArray* objects) {
    NSLog(@Lignes récupérées du WebService : %@", objects)
    }];
  • tabliertablier Membre
    septembre 2014 modifié #6

    Ne t'inquiète pas trop. Ce n'est pas prévu pour être diffusé. C'est prévu pour être utilisé à  poste fixe, au domicile de l'association et uniquement par un permanent et un bénévole.


    J'avais l'intention d'essayer une queue d'opération (NSOperationQueue) mais je vais me fier à  notre référence documentaire et essayer ce que tu indiques.   o:)  .


    J'ai aussi trouvé cela qui est voisin, ce qui me fait deux essais à  prévoir:



    - (void)grabURLInBackground


    {

       NSURL *url = [NSURL URLWithString:@"http://allseeing-i.com"];

       ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];

       [request setDelegate:self];

       [request startAsynchronous];

    }

     

    - (void)requestFinished:(ASIHTTPRequest *)request

    {

       // Use when fetching text data

       NSString *responseString = [request responseString];

     

       // Use when fetching binary data

       NSData *responseData = [request responseData];

    }

     

    - (void)requestFailed:(ASIHTTPRequest *)request

    {

       NSError *error = [request error];

    }


     


    Je n'ai pas trop de temps en ce moment, mon 3me fils à  fait construire une maison et je suis plus occupé par le bâtiment que par l'informatique!! Bon, il y a un temps pour tout.


  • AliGatorAliGator Membre, Modérateur
    septembre 2014 modifié #7
    ASIHTTPRequest !! Le dinosaure du passé !! ça fait genre 3 ans que je l'ai pas vu celui-là  !! (et pour cause, il est déprécié depuis qqch comme 2 ans déjà  et abandonné depuis un bail maintenant). Oublies-le de toute urgence !!




    Pour faire des requêtes réseau proprement tu as

    Dans le SDK Apple :

    - NSURLConnection (lasse historique)

    - NSURLSession (classe plus récente, plus flexible et ouvrant + de possibilités de configuration, mais dispo que depuis les dernières versions d'iOS et OSX

    En librairie tierce (donc à  intégrer à  ton projet avec CocoaPods) :

    - AFNetworking (Lib ObjC codée par le fameux Mattt Thompson)

    - Alamofire (son équivalent en Swift, par Mattt Thompson également) si jamais tu codais en Swift


    Mais en aucun cas ASIHTTPRequest qui date de mathusalem et est officiellement abandonné par son auteur (qui recommande lui même AFNetworking au passage maintenant) depuis un bout de temps ;-)


    Maintenant avec NSURLSession tu peux faire quasiment tout ce dont tu as besoin dans 80% des cas donc dans ton cas c'est amplement suffisant.


    ---


    PS : Le fait que l'application soit à  vocation d'être tjs sur un ordi fixe et ne soit pas distribué n'est en aucun cas une excuse pour faire du mauvais code synchrone et bloquant le mainThread. Autant prendre les bonnes pratiques dès le début plutôt que se créer des mauvaises habitudes, d'autant que pour le coup c'est pas comme si ça transformait ton code de façon compliquée et rajoutait une énorme complexité : le code tient en autant de lignes qu'avant ou presque.
  • tabliertablier Membre
    septembre 2014 modifié #8

    Terminé la peinture des murs pour aujourd'hui!!


     


    Tu as raison si tu es sous 10.8 ou 10.9.  Malheureusement l'association n'a pas les moyens d'avoir des machines récentes!  Je travaille sous 10.9 chez moi, mais là  je dois compiler pour ppc + Intel sous 10.5 ou 10.6. Donc je compile sous 10.6 avec Xcode 3.2.6 qui est le dernier à  permettre de compiler pour ppc. Mais je vais essayer sous 10.9 quand même pour leur faire tirer la langue !


     


    Juste pour te situer le problème: L'association a démarrer il y a 18 ans à  peu près. A cette époque là , toutes les écoles de Grenoble (INPG, INRIA, Fac ....) voulaient participer, les administrations et les entreprises du secteur d'activité faisaient des contrats de financement et l'association tournait bien. Aujourd'hui, l'association à  un peu plus de 2500 machines réparties sur trois niveaux d'un grand bâtiment, mais les financements qui sont toujours présents n'ont pas suivis le coût de la vie et ont plutôt diminué! Je ne suis la dedans (en pointillé) que depuis 3 ou 4 ans et je me limite à  faire marcher de vieux appareils car l'association fait des expositions et présenter des appareils en fonctionnement est un plus. Comme exemple: voici la machine sur laquelle je travaille en ce moment (en plus du problème exposé dans ce post). C'est un terminal "Digital LetterWritter100" dont je recherche vainement les plans: 


    P825.jpg 100.5K
  • AliGatorAliGator Membre, Modérateur
    Raison donc supplémentaire pour utiliser NSURLConnection (qui existe depuis les débuts) et surtout pas du chargement synchrone si en plus les machines ne sont pas des machines de guerre !!!!!!
  • tabliertablier Membre
    septembre 2014 modifié #10

    Raison donc supplémentaire pour utiliser NSURLConnection (qui existe depuis les débuts)



    Tu as raison et c'est vrai pour NSURLConnection, mais sendAsynchronousRequest:  n'existe que depuis 10.7.  Sous 10.5 et 10.6 il n'existait que sendSynchronousRequest. 


    Je verrai ça demain soir quand je serrai en montagne, j'ai assez bossé pour aujourd'hui. 


  • AliGatorAliGator Membre, Modérateur
    Oui pas avant ça tu pouvais utiliser les delegates pour charger des données de façon asynchrones quand même ;-)
  • Pour info, j'ai terminé ce que je voulais faire. J'utilise NSURLConnection et  NSURLCache et  le téléchargement est asynchrone.


    Je n'ai pas honte de le dire, une partie du code vient de l'exemple "CacheInfo-MacOSX" d'Apple.


     


       ::)   La Doc (c'est lui) a encore frappé !


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