2017-09-27 6 views
0

J'ai le scénario suivant - J'ai une application qui a besoin d'obtenir des fichiers audio du serveur en arrière-plan et de manière asynchrone. Les fichiers audio sont un grand nombre - comme 10000. Ils sont 1-2 fichiers mp3 sec (comme 5-10 kb chacun). Pour chacun de ces fichiers, je dois faire une requête réseau et obtenir les fichiers en utilisant son identifiant. Il existe deux types de fichiers audio - pour votre langue maternelle et pour votre langue d'apprentissage. Donc, je passe par tous les ID comme ça - 1. me procurer l'audio natif avec ID 1, puis me faire apprendre l'audio avec ID 1 ---> ID + 1 et encore le même scénario. Le problème est que quand je vais comme ça, certains fichiers audio sont corrompus à la fin. Je suppose que c'est parce que je ne fais pas correctement les requêtes asynchrones. Voici mon code:Comment faire plusieurs requêtes réseau une par une pour ne pas perdre de données?

DispatchQueue.global(qos: .background).async { 
let myGroup = DispatchGroup() 

for category in arrCategories { 
    for library in category.libraries { 
     for group in library.groups { 
      for word in group.words { 

       myGroup.enter() 

       User.current.getAudioFile(forWord: word, language: User.current.nativeLanguage, isNative: true, callback: { (success) in 
        if success { 
         User.current.getAudioFile(forWord: word, language: User.current.learningLanguage, isNative: false, callback: { (success) in 
          if success { 
           myGroup.leave() 
          } else { 
           print("ERROR LEARNING") 
           myGroup.leave() 
          } 
         }) 
        } else { 
         print("ERROR NATIVE") 
         myGroup.leave() 
        } 
       }) 
      } 
     } 
    } 
} 

myGroup.notify(queue: DispatchQueue.main, execute: { 
    print("READY") 
    running = false 
}) 

Et ma demande de réseau:

 request(urlRequest).response { (response) in 

      if response.data != nil && response.error == nil { 
       let soundData = response.data! as NSData 
       let fileURL = URL(fileURLWithPath: filePath) 

       do { 
        try soundData.write(to: fileURL, options: .atomic) 
        callback(true) 
       } catch { 
        print(error) 
        callback(false) 
       } 
      } else { 
       print(response.error?.localizedDescription) 
       callback(false) 
      } 

Quelqu'un peut-il me dire ce qui ne va pas avec le code? Parce que certains fichiers audio ne jouent pas si j'utilise cette approche. Mais si je télécharge seulement ce fichier sans faire autant de demandes, il joue normalement.

Répondre

1

L'utilisation d'une boucle lance simplement toutes les demandes asynchrones. Votre problème réside dans le traitement de toutes les réponses parallèles.

Une option consiste à utiliser un mutex/semaphor pour bloquer la boucle avant de terminer la première (je ne le conseille.

La deuxième option serait de créer une liste de demande et à chaque fois qu'une finition de demande de départ ... la prochaine

1

Certainement un emploi pour un OperationQueue et BlockOperation Avec BlockOperation vous pouvez même ajouter la dépendance de l'un à l'autre et assurez-vous que tous sont exécutés

Voici une idée (code non testé):

var queue = OperationQueue() 
var previousOp: BlockOperation ? = nil 
for task in tasks { 
    let op = BlockOperation { your code } 
    if previousOp != nil { 
     previousOp.addDepencendy(op) 
    } 
    previousOp = op 
}