(Réglé) Traitement d'une requête très long (presque 20 secondes)

124»

Réponses

  • Nasatya, si tu regardes le code plus haut, j'ai effectué ce changement ?


     


    Muqaddar quels outils ? J'avais essayé Instruments sauf que je ne sais pas l'utiliser et je ne sais pas a quel "Symbol name" ça correspond, donc si vous m'expliquer je veut bien vous dire les résultat ;)


  • Non je le vois pas dans le dernier code que tu as partagé il n'y a pas la modification...


  • Ah mais autant pour moi, en fait j'étais de base en mainQueue et quand j'ai vu ton message je suis passé en alloc init d'où la confusion.


     


    Et la d'un coup ça va beaucoup mieux la requete met 2 secondes, merci c'est enfin réglé


  • Bon n'oublie pas d'ajouter la condition sur le strResult pour le cas ou il serait vide histoire de pas avoir d'ennuis (même si le cas ne devrait pas arriver normalement on est jamais assez prudent) et si la vie le veut bien ça devrait fonctionner;)





  • if ([strResult count] > 0)
    {
    //Le code ici
    }



    Celui la ?

  • AliGatorAliGator Membre, Modérateur
    Conclusion, c'était bien le fait de faire du synchrone et la méthode non standard d'utiliser une dispatch_queue + sendSynchronous qui faisait que ta requête prenait 20s. un sendAsynchronous a fait passer ce temps à  2s.

    Après, vu tous les petits à -côté que tu as eu, il serait peut-être bon de faire un peu de ménage dans ton code pour le rendre plus propre et t'éviter de t'y perdre (et nous y perdre aussi) comme c'est arrivé pendant tout ce thread. Et en profiter pour te former un peu sur le net ou autre sur les bonnes pratiques / astuces de déboguage (breakpoints, Instruments, etc). Et passer à  GIT pour profiter de tous les avantages qu'il t'aurait apporté pour te faciliter la comparaison du code avant/après & co ;)
  • Oui tu avais raison depuis le début, you're the boss ^^


     


    Faire le ménage dans mon code c'est à  dire ? Si tu pouvais m'éclairer


  • @Ben77650  oui ce test là .


    @AliGator un énorme +1


  • C'est fait Nasatya, merci du conseil


  • zoczoc Membre


    Alors qu'il est si simple de faire du SSL (tellement standard que ça n'ajoute rien à  ton code et est géré par le système) et ensuite de pouvoir faire transiter son mdp en Basic Auth sans avoir de crainte qu'il soit visible vu que l'échange SSL est chiffré...




     


    C'est vrai, pour peu que le client vérifie scrupuleusement le certificat présenté par le serveur, ce qui est fait trop peu souvent, car sinon la connexion chiffrée est vulnérable aux attaques Man In The Middle...

  • Bon j'essaye d'adapter le traitement asynchrone à  tout ce qui appelle un webservice, mais je bloque arriver à  ce niveau la



    -(NSArray*)getImageFromId:(NSObject*) entier
    {
        NSURL *link = [NSURL URLWithString:[NSString stringWithFormat:@%@", @http://www.mywebsite.org/getImagesOffers.php]];
        NSMutableURLRequest *URLrequest = [NSMutableURLRequest requestWithURL:link];
        
        NSString *post = [NSString stringWithFormat:@clé=%@",entier];
        
        
        
        post = [post stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
        NSData *dataRequest = [post dataUsingEncoding:NSUTF8StringEncoding];
        URLrequest.HTTPBody = dataRequest;
        URLrequest.HTTPMethod = @POST;
        
        
        
            NSError *httpError = nil;
            [NSURLConnection sendAsynchronousRequest:URLrequest queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
        
                if ([data length] >0 && httpError == nil)
                {
                    id stringResult=nil;
                    int cmpt;
                    NSError* error1;
                   stringResult = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error1];
                    if([stringResult count]>0)
                    {
                    _tabImg = [[NSMutableArray alloc]init];
        
                    for(cmpt=0; cmpt<[stringResult count];cmpt++)
                    {
                        NSDictionary *tempDic = [stringResult objectAtIndex:cmpt];
                        [_tabImg addObject:[tempDic objectForKey:@nom]];
        
                    }
        
                    return _tabImg;
                    }
                }
        
        
             else if ([data length] == 0 && httpError == nil)
             {
                 UIAlertView *vide = [[UIAlertView alloc] initWithTitle:@Erreur
                                                                message:@Rien n'a été téléchargé
                                                               delegate:nil
                                                      cancelButtonTitle:@OK
                                                      otherButtonTitles:nil];
                 [vide show];

             }
             else if (httpError != nil){
                 NSString* err=[NSString stringWithFormat:@Error = %@", httpError];
        
                 UIAlertView *erreur = [[UIAlertView alloc] initWithTitle:@Erreur
                                                                  message:err
                                                                 delegate:nil
                                                        cancelButtonTitle:@OK
                                                        otherButtonTitles:nil];
                 [erreur show];
            }
        
        }];
    }

    Seul souci il n'apprécie pas vraiment et me sors cela


     


    Incompatible block pointer types sending 'NSMutableArray *(^)(NSURLResponse *__strong, NSData *__strong, NSError *__strong)' to parameter of type 'void (^)(NSURLResponse *__strong, NSData *__strong, NSError *__strong)'

     



    Je n'arrive pas également à  savoir quelle valeur lui retourner dans les cas d'erreur donc forcément il me dit cela:


     


    Control may reach end of non-void block

     


  • Oui c'est normal que ça fonctionne pas je te laisse aller voir la documentation sur les block parce qu'on a déjà  mis 6 pages pour expliquer l'asynchrone là  c'est autrement plus technique...


     


    En bref tu peux pas faire un return comme ça dans un block il faut que tu transforme ta fonction "getImageFromId" en block également et que ce block fasse un complétion contenant un array et tu appelera ta fonction de complétion dans ton block.


     


    Mais là  c'est documentation et tuto et à  la limite quelques questions dans les forums.


     


    C'est la qu'on se rend compte que le synchrone c'est vraiment pas adapter à  toute les situations mais qu'est ce que c'est simple a gérer.


  • Euh... Je ne veux pas tirer la couverture à  Nasatya et moi mais... c'était pas plutôt d'executer le completionHandler dans une background queue qui posait problème ?

  • J'ai fait quelques essais avec Instruments et il semble qu'effectivement sendAsynchronousRequest n'appelle pas sendSynchronousRequest.


    Je pense que c'était peut-etre vrai dans iOS 6 mais dans iOS 7, sendAsync utilise NSURLSession. 

  • AliGatorAliGator Membre, Modérateur
    Je pense pas que c'était vrai dans iOS6 car ça voudrait dire qu'Apple aurait fait exactement l'erreur qui a été faite ici, à  savoir rendre asynchrone un truc qui rendait synchrone un truc qui faisait déjà  de l'asynchrone. Ce serait peindre un truc en rouge puis en bleu alors qu'il était déjà  bleu à  l'origine...
  • Je me base uniquement sur le thread stackoverflow (qui dit iOS 5 pas 6) mais cela me parait plausible.

    http://stackoverflow.com/questions/11526862/dispatch-async-and-nsurlconnection-sendsynchronousrequest


    Enfin je voulais juste appuyer sur le fait que ce n'est pas mal d'utiliser une version synchrone d'un traitement dans une queue.

    Sauf que là , Apple semble avoir delaissé cette méthode et qu'elle est en fait mal ecrite derriere, ce qui est dommage.


    Par exemple quand on a deja un thread d'arriere plan et qu'on a envie d'avoir un code linéaire, un peu comme on le ferait naturellement dans un script, on peut utiliser du synchrone.

    Avec les blocks, on n'a plus besoin de créer un delegate et d'avoir du code en morceaux un peu partout, c'est déjà  un progrès, mais parfois on se retrouve a enchainer des blocks dans des blocks et ça devient franchement illisible.


    Le seul vrai problème conceptuel du synchrone, c'est qu'on ne peut pas l'annuler quand c'est parti.


    Maintenant je suis d'accord que créer un thread ou une queue, juste pour lancer sendSynchronousRequest, c'est un peu couillon et que dans 80% des cas, je conseillerais la version asynchrone.

    Mais je ne crois pas qu'on puisse dire que la version synchrone est dix fois moins rapide que la version asynchrone.
  • AliGatorAliGator Membre, Modérateur
    Elle l'est car elle spawn un tas de threads inutilement, alors que la version asynchrone se base sur la RunLoop et évite le thread-spamming et donc d'engorger ton appli et de risquer que le scheduleur soit débordé à  perdre plus de temps à  switcher entre les threads qu'à  effectivement les exécuter (d'où le fait que ça prend alors vachement + de temps quand tu fais du thread-spaming que quand tu schedule correctement).

    Encore une raison donc de ne pas réinventer la roue quand on ne maà®trise pas bien tous les principes, tenants et aboutissants autour de la Concurrency et du MultiThreading, et d'utiliser les méthodes déjà  prévues qui font déjà  ça très bien plutôt que de s'emmêler tout seul les pinceaux en essayant de faire ça nous-même.
Connectez-vous ou Inscrivez-vous pour répondre.