1

Ma bibliothèque expose 2 API comme suit pour:Obliger l'ordre d'exécution à l'aide dispatch_sync

-(void) createFile{ 

    dispatch_sync(queueSerial, ^{ //B1 

    [fileObj createFileInfo:file completion:^(NSError *error){ 

     //execute completion block C1 
    }]; 

    }); 
} 

-(void) readFile:(NSData*)timeStamp{ 

    dispatch_async(queueSerial, ^{ //B2 

     [fileObj readFileInfo:fileName completion:^(NSError *error) { 
      dispatch_async(queueSerial2, ^{ 

       //execute completion block C2 

      }); 
     }] 

    }); 
} 

Les deux readFile et createFile sont des méthodes asynchrones.

Je recommande généralement aux personnes utilisant ma bibliothèque d'appeler createFile avant readFile. Cependant, il n'y a aucune garantie que les appelants finiront par l'implémenter. Il obtient habituellement invoqué de la manière suivante (et je aucun contrôle sur cette)

[fileClass createFile]; 
[fileClass readFile:timeStamp]; 

Ce que je veux faire est d'assurer readFile est appelée après la completion block C1 est exécutée. Je ne veux pas non plus bloquer le thread principal avec createFile (mais cette attente peut être assouplie). Donc ce que je veux atteindre comme résultat final est:

  1. appelant (que je ne contrôle pas) appelle createFile et immédiatement après les appels readFile
  2. createFile exécute complètement, bloc d'achèvement C1 est congédié et après que, readFile est expédiée pour faire ce que vous voulez.

Comment puis-je y parvenir?

+0

@Rob merci pour la perspicacité.Je suis un jeune débutant (en Obj. C) à ce stade donc je vais essayer de suivre votre suggestion désormais. – ExceptionHandler

+0

Comment 'readFile' renvoie-t-il les données qu'il a lues? Il est défini pour renvoyer 'void', donc il doit utiliser un gestionnaire de fin ou un modèle de délégué? – Rob

+0

@Rob 'readFile' transmet les données (valeur d'erreur le cas échéant) dans le gestionnaire de complétion C2. Je ne savais pas si ces parties étaient pertinentes. – ExceptionHandler

Répondre

1

Il semble que vous essayiez de prendre une API existante basée sur un gestionnaire d'achèvement et de l'insérer dans un modèle de file d'attente série. Mais les files d'attente en série n'ont de sens que lorsque les blocs distribués sont eux-mêmes synchrones. (Et ne confondez pas ceci avec dispatch_sync ... nous parlons si la tâche à l'intérieur du bloc est asynchrone ou pas, pas comment vous l'avez expédiée à votre file d'attente.) Mais vous avez affaire à des méthodes asynchrones appelées d'autres méthodes asynchrones. Le modèle de base pour les méthodes prenant des blocs de gestionnaires d'achèvement est d'éliminer complètement la file d'attente série (aucune file d'attente GCD n'est nécessaire ou utile lorsque les tâches sont déjà asynchrones) et d'utiliser simplement des blocs de gestionnaire d'achèvement dans vos propres méthodes et faites le dernier appel dans le bloc le plus imbriqué appelez votre propre gestionnaire d'achèvement.

Par exemple:

- (void)foo:(void (^)())completion { 
    [fileObj setFileInfo:file completion:^(NSError *error) { 
     // do some other stuff 
     completion(); 
    }]; 
} 

- (void)bar:(void (^)())completion { 
    [fileObj getFileInfo:fileName completion:^(NSError *error) { 
     // do some other stuff 
     completion(); 
    }]; 
} 

Et alors vous l'appelez comme ceci:

[self foo:^{ 
    [self bar:^{ 
     // do whatever you want when its all done 
    }]; 
}]; 

Cela signifie qu'il ne fera pas des choses getFile jusqu'à ce que les choses se fait setFile . Cela dit, je me demande ce que vos méthodes setFile et getFile ajoutent au-delà des méthodes propres aux classes FileObject. Mais la clé est que lorsque vous traitez avec des méthodes asynchrones, vous ne pouvez pas facilement les coordonner avec une simple file d'attente GCD série. Si vous souhaitez que le comportement de la file d'attente de répartition soit asynchrone pour les tâches qui sont elles-mêmes asynchrones, vous devriez généralement utiliser des files d'attente d'opérations à la place (ou promesses/futures ou quelque chose comme ça).

+0

Je comprends ce que vous essayez de dire mais la chose est que je n'ai que le contrôle sur les méthodes 'setFile'' getFile' et * pas * sur la façon dont elles sont invoquées malheureusement. Donc, j'ai besoin de contourner la limitation. Le mieux que je peux faire est de forcer l'envoi de 'getFileInfo' après que 'setFileInfo' a fini – ExceptionHandler

+0

Ensuite, vous devriez éditer votre question partager comment ils sont appelés (et expliquer pourquoi ils ne peuvent pas être changés). Mais la vérité fondamentale ici est que vous ne pouvez pas simplement prendre des méthodes asynchrones et les ajouter à une file d'attente et s'attendre à ce que la file d'attente gère cela. Vous pouvez, théoriquement, les rendre synchrones, mais c'est une idée vraiment horrible (pour beaucoup de raisons). Si vous le souhaitez, vous pouvez créer ces sous-classes asynchrones 'NSOperation', mais cela modifie aussi votre API (et bien que ce soit plutôt cool, cela demande plus de travail à faire correctement). S'il vous plaît, éditez simplement la question impliquant quelles contraintes vous avez sur votre API ... – Rob

+0

en ce qui concerne la valeur ajoutée par ces méthodes, ce sont les seules méthodes de cette classe 'FileObject' qui sont exposées aux clients appelant dans mon processus. Je ne suis pas complètement opposé à l'utilisation d'autres méthodes pour y parvenir. C'est juste que la méthode 'setFile' est lourde et doit être exécutée avant que' getFile' ne soit appelé avec son timeSTamp' sensible au temps – ExceptionHandler