Attente de completion block

AliAli Membre

Bonjour, 


 


Je fais face à  un problème pour la première fois, en effet le retour de ma méthode dépend d'une valeur modifiable dans le block, je vous donne l'exemple :



BOOL __block found = NO;
[bookings retrieveAllBookings:^(NSArray * bookings, NSError * error){
for (Reservation *resa in bookings) {
if ([(Reservation*)resa checkIn] ) {
found = YES;
}
}

}];
return found;
 

C'est quoi le moyen le plus approprié pour attendre la fin d'execution de ce Block pour retourner cette valeur. 


 


Réponses

  • Joanna CarterJoanna Carter Membre, Modérateur
    mars 2015 modifié #2
    Pourquoi telle complexité ? Aucun besoin d'un block.
    {  NSPredicate *predicate = [NSPredicate predicateWithFormat:@checkIn == YES];    NSArray *checkedInBookings = [bookings filteredArrayUsingPredicate:predicate];}
    En plus :


    1. Tu as une méthode nommé retrieveAllBookings mais tu ne les récupères pas ; en revanche, tu les fouilles.


    2. Tu as dupliqué "bookings" une fois dans l'appel et la deuxième fois dans les paramètres.


    3. Le cast vers Reservation sur chaque article de la liste ne sert à  rien parce que le for..in ne passe que le Reservations.
  • AliAli Membre

    Hello, merci pour la réponse,


     


    retrieveAllBookings est une méthode qui fait appel à  un web service. La variable bookings est un array retourné à  partir de cette méthode là , du coup la solution des predicate n'est pas la plus approprié. 


     


    Je reviens sur ma question initial, c'est comment attendre le block qu'il finisse ?


     


    merci


  • zoczoc Membre
    mars 2015 modifié #4

    Je reviens sur ma question initial, c'est comment attendre le block qu'il finisse ?

    Un bloc, ce n'est pas un thread, c'est juste équivalent à  une fonction C (en fait, grosso modo, quand tu utilises un bloc, le compilateur va générer une fonction à  ta place). Donc si l'exécution du bloc est asynchrone, c'est parce que l'implémentation de retrieveAllBookings fait qu'elle l'est, et de l'extérieur de cette méthode tu n'as aucun contrôle sur ce fait. Il faut donc modifier l'implémentation de retrieveAllBookings... Sur d'autres plateformes (.NET par exemple) tu as d'autres techniques (Async/Await) qui permettent des choses qui n'ont pas d'équivalent sur iOS/OSX et qui permettraient de faire ce que tu veux faire.

    Mais de toute façon, je pense qu'il n'est pas approprié d'attendre, car si ton code est appelé dans le thread principal, alors cela résultera en des blocages de l'interface graphique, et c'est mal.

    Il faut organiser le code différemment de manière à  ne pas avoir besoin d'attendre...
  • Joanna CarterJoanna Carter Membre, Modérateur
    mars 2015 modifié #5

    OK, bon.


     


    Normalement, les chemins de code qui passent par un block se terminent là , car ils sont exécutés sur un autre thread que le thread principal.


     


    Du coup, c'est aussi normal à  modifier le UI du code d'un block, en utilisant un appel dispatch_async qui se tournera sur le thread principal.


     


    Je te demanderais, qu'est-ce qui devrait se passer après le retour de ta méthode qui passe le block au web service ?


     


    Je me trouve d'accord avec zoc en disant que, peut-être, il faut reorganiser ton code pour qu'il prenne en compte les threads, en espérant que le code du web service n'exécute pas sur le thread principal.


     



    La variable bookings est un array retourné à  partir de cette méthode là , du coup la solution des predicate n'est pas la plus approprié.



     


    Au contraire, tu peux, quand même, utiliser un predicate à  la place du for..in



    {
    [bookings retrieveAllBookings:^(NSArray * bookings, NSError * error
    {
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@checkIn == YES];

    NSArray *checkedInBookings = [bookings filteredArrayUsingPredicate:predicate];

    if (checkedInBookings.count > 0)
    {
    // mettre à  jour le UI
    }
    }];
    }

  • AliGatorAliGator Membre, Modérateur
    Si ta méthode (que tu es en train d'écrire et dont tu nous a donné le code) appelle une méthode asynchrone (en l'occurrence retrieveAllBookings) c'est donc que par nature ta méthode devrait elle aussi être asynchrone.

    Donc puisque le fait de savoir si on a trouvé des éléments passe par retriveAllBookings et un WebService et donc par nature peut prendre du temps etc, ta méthode parent (qu'on va appeler "hasCheckedIn" par exemple) ne doit pas être une méthode qui retourne un BOOL (la valeur de "found" dans ton cas), mais une méthode qui ne retourne rien dans l'immédiat, et fournit la valeur de résultat au travers d'un bloc de complétion. Puisque pour savoir si tu as des réservations Checked-In, par nature cela se fait de manière asynchrone. Faut rester logique.

    Faire une méthode synchrone qui va être obligée d'attendre que le block soit fini d'exécuter n'est pas une bonne idée car tu transformes du asynchrone (te permettant de continuer ton code sans bloquer ton thread principal pendant que la requête WebService est faite et la réponse analysée) en code synchrone donc bloquant, qui va bloquer le thread appelant en attendant d'avoir la réponse (ce qui peut être long si le réseau de l'utilisateur est pourri ou qu'il passe sous un tunnel !). Du coup si tu te mets à  transformer du asynchrone en synchrone c'est sûrement qu'il y a un problème de conception. C'est possible dans l'absolu, mais c'est souvent révélateur d'une mauvaise idée.
Connectez-vous ou Inscrivez-vous pour répondre.