6
votes

Attendre que des méthodes asynchronisent se terminent dans une boucle

J'ai un pour boucle contenant trois méthodes asynchrones et je tiens à faire un traitement après que ces 3 méthodes asynchronisées soient terminées.

 -(void)getAllUsersInformations{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
           for(User *user in users){
              [self getUserInfo:user];
           }
      //Here, I want to reload the table view for example, after finishing the for loop (executing the whole three methods).
    });
}

-(void)getUserInfo:(User*)user{
     [self getInformations:user];
     [self getExperiences:user];
     [self getEducation:user];
}


4 commentaires

Sont getinformations , getExperiences et getEducation , eux-mêmes, méthodes asynchrones? Ou sont-ils toutes des méthodes synchrones que vous expédieriez de manière asynchrone à une file d'attente de fond? (Votre édition à la question change radicalement la réponse.)


@Rob ; Oui, ils sont asynchrones! GetAlluSersInformations GetInformations GetExperiences et GetEducation est asynchrone.


@androniennn pouvez-vous faire les trois -getxxx méthodes synchrones?


@Aarona. Non, ce n'est pas possible, ils doivent être asynchronisés.


4 Réponses :


-1
votes
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    // Background work
       for(User *user in users){
          [self getUserInfo:user];
       }

    dispatch_async(dispatch_get_main_queue(), ^{
     //reload tableview , this is on main thread.
    });
});

4 commentaires

Les trois méthodes dans -GettuserInfo: sont asynchrones, qui ne vont pas que cela revienne tôt?


@Aarona. : Exactement Aaron.


Non, ces méthodes seront appelées synchroneusement sur fond. En effet, si vous mettrez un point d'arrêt sur la saisie du bloc, cela passera dessus. Lorsque la boucle pour la boucle sera terminée, le bloc DisPatch_ASync (DisPatch_Get_Main_Quue (), ^ {// Recharger la tableView, ceci est sur le fil principal.}); sera appelé sur le fil principal. Faites un test rapide, cela devrait fonctionner.


@ADIPOP, les trois méthodes sont asynchrones, dans un bloc Dispatch_ASync. Le rechargement de la TableView sera exécuté avant la finition exécutant les 3 méthodes.



0
votes

Essayez de faire un bloc avec l'achèvement, vous ne pouvez pas le faire avec une boucle si les méthodes sont asynchronisées. Vous devez appeler getuserinfo un par un après l'achèvement de la précédente. Je pense que cela va être résolu votre problème.

  -(void)getAllUsersInformations{
    [self registerUserAtIndex:0];
  }

  - (void) registerUserAtIndex: (NSInteger ) userIndex
  {
  RegisterOperation *op = [[RegisterOperation alloc] initWithUser:[users objectAtIndex:userIndex]];
  [RegisterOperation setResultCompletionBlock:^(BOOL *finished, NSInteger userIndex) {
      dispatch_async(dispatch_get_main_queue(), ^{
      if (userIndex++ < [users count] {
         [self registerUserAtIndex:userIndex++];
      } else {
         [myTableView reloadData];
      }
   }];
  [[NSOperationQueue mainQueue] addOperation:op];
 }


0 commentaires

15
votes

Une approche GCD consiste à utiliser Dispatch_group code>. Donc, avant de démarrer une tâche asynchrone, appelez DisPatch_group_enter code>, puis lorsque la tâche asynchrone se termine, appelez DisPatch_group_leave code>, et vous pouvez ensuite créer un DisPatch_group_notify code > Qui sera appelé lorsque les tâches asynchrones finissent. Vous pouvez épouser cela avec un modèle de bloc d'achèvement (qui est une bonne idée pour les méthodes asynchrones, de toute façon):

  1. si getInformations code>, getExperiences code> et getEducation code> sont, eux-mêmes, toutes les méthodes asynchrones, la première chose dont vous avez besoin est un mécanisme pour savoir quand ils sont terminés. Une solution commune consiste à mettre en œuvre un modèle de bloc d'achèvement pour chacun. Par exemple: p>

    // call new getUserInfo, using dispatch group to keep track of whether
    // all the requests are done
    
    -(void)getAllUsersInformations {
    
        dispatch_group_t group = dispatch_group_create();
    
        for(User *user in users){
            dispatch_group_enter(group);
    
            [self getUserInfo:user completionHandler:^{
                dispatch_group_leave(group);
            }];
        }
    
        dispatch_group_notify(group, dispatch_get_main_queue(), ^{
            [self.tableView reloadData];
        });
    }
    


4 commentaires

Quelle explication! Compris la technique, et je vais essayer de le mettre en œuvre. Je laisserai un retour d'information;).


Le dernier group_notify qui rechargne la vision de la table n'est jamais appelé. Je ne sais pas pourquoi, surtout comme le group_leave de getuserinfo est appelé.


Tout d'abord, assurez-vous que le groupe final notify n'a pas été appelé (et que ce n'est pas simplement un problème que la recharge de la table n'a pas fonctionné correctement). Deuxièmement, pour diagnostiquer ceci, connectez-vous dans le groupe Entrer et congé dans GetAllUserSinformations et assurez-vous qu'ils Tous ont été appelés.


Merci beaucoup voler, ça fonctionne comme je voulais. Merci aussi pour les pensées finales, les 2) - Je l'ai déjà à l'esprit et pour le premier, je dois lire le Doc et peut-être le changer comme vous avez conseillé. Merci :) ...



0
votes

ROP Réponse avec SWIFT STRAND>:

func processData()
{
    let group: dispatch_group_t  = dispatch_group_create()

    for item in data as! Object {
        dispatch_group_enter(group)
        item.process(completion: {() -> (Void) in
          dispatch_group_leave(group)
        })
      }

    dispatch_group_notify(group, dispatch_get_main_queue(), {
        //Do whatever you want
      })
}


0 commentaires