2017-03-08 1 views
2

J'essaie d'envoyer plusieurs photos de mon API en itérant un tableau d'images. Je veux envoyer chaque image dans un fil différent mais quand le fil de poing finit il n'attend pas pour le reste des discussions et une seule image est envoyée.Swift 3: Exécuter plusieurs threads et attendre la finalisation

Ceci est mon code:

// create the concurrent queue 
    let asyncQueue = DispatchQueue(label: "asyncQueue", attributes: .concurrent) 

    // perform the task asynchronously 
    for image in self.arrayImages{ 
     asyncQueue.async() { 
      let strBase64:String = image.base64EncodedString(options: .lineLength64Characters) 
      self.sendImage(image: strBase64) 
     } 

    } 

J'ai récemment commencé à programmer à Swift et je ne sais pas comment synchroniser les threads. Pourrais-tu m'aider s'il te plait?

Le code pour faire mes demandes est:

// Función para mandar a la API la petición de añadir una imagen a la idea 
func sendImage(image:String){ 
    let data = NSMutableDictionary() 

    let id:Int = (idea?.id)! 
    let pasoAct = idea?.pasoActual 
    data["id_idea"] = id 
    data["id_paso"] = pasoAct 
    data["contenido"] = image 

    let jsonData = try! JSONSerialization.data(withJSONObject: data, options: JSONSerialization.WritingOptions(rawValue: 0)) 
    let request = NSMutableURLRequest(url: NSURL(string:"http://192.168.2.101:3001/api/imagen") as! URL) 
    request.httpMethod = "POST" 
    request.addValue("application/json", forHTTPHeaderField: "Content-Type") 
    request.addValue("application/json", forHTTPHeaderField: "Accept") 
    request.httpBody = jsonData 

    URLSession.shared.dataTask(with: request as URLRequest, completionHandler: self.responseImage).resume() 
} 
// Función de control de la respuesta del servidor tras enviar una imagen 
func responseImage(data: Data?, response: URLResponse?, error: Error?) { 

    if (error != nil) { 
     print("No se ha podido contactar con el servidor") 
    } 
    else{ 
     // Connected, check response, GET status codes. 
     let statusCode = (response as! HTTPURLResponse).statusCode 

     switch statusCode{ 
      case 200: 
       print("Imagen subida") 

      default: 
       print("Error en la petición al servidor") 
     } 
    } 
} 

La première image est téléchargée correctement (réponse renvoie le code d'état = 200), mais prochaines images ne

C'est le code que j'ai modifié suivant vos conseils:

func sendImage(image:String, completion: @escaping() -> Void) { 

    let data = NSMutableDictionary() 

    let id:Int = (idea?.id)! 
    let pasoAct = idea?.pasoActual 
    data["id_idea"] = id 
    data["id_paso"] = pasoAct 
    data["contenido"] = image 

    let jsonData = try! JSONSerialization.data(withJSONObject: data, options: JSONSerialization.WritingOptions(rawValue: 0)) 
    let request = NSMutableURLRequest(url: NSURL(string:"http://192.168.2.101:3001/api/imagen") as! URL) 
    request.httpMethod = "POST" 
    request.addValue("application/json", forHTTPHeaderField: "Content-Type") 
    request.addValue("application/json", forHTTPHeaderField: "Accept") 
    request.httpBody = jsonData 

    URLSession.shared.dataTask(with: request as URLRequest) { (data, response, error) in 
     self.responseImage(data: data, response: response, error: error) 

     // When responseImage is complete, call the completion handler 
     completion() 
    } 
} 


// And the following code is called when I try to send the array of images 
let group = DispatchGroup() 
    let asyncQueue = DispatchQueue(label: "asyncQueue", attributes: .concurrent) 
    for image in self.arrayImages { 

     asyncQueue.async { 
      group.enter() 

      let strBase64:String = image.base64EncodedString(options: .lineLength64Characters) 
      self.sendImage(image: strBase64) { 
       group.leave() 
      } 
     } 
    } 

    group.wait() 

Répondre

1

Dans votre cas, il peut être préférable d'utiliser concurrentPerform:

DispatchQueue.concurrentPerform(iterations: self.arrayImages.count) { i in 
    let strBase64 = self.arrayImages[i].base64EncodedString(options: .lineLength64Characters) 
    self.sendImage(image: strBase64) 
} 

print("Done") // This line will only be executed after self.send() is 
       // called on all images. However, this does not mean that 
       // the server has received all the images. 
+0

convenu. dans le cas où tous les asyncs exécutent fondamentalement le même code, je recommanderais aussi ceci –

+0

ne fonctionnait pas pour moi :( –

1

Vous pouvez utiliser un DispatchGroup ...

let group = DispatchGroup() 

for image in self.arrayImages { 

    let workItem = DispatchWorkItem(qos: .default, flags: []) { 
     let strBase64:String = image.base64EncodedString(options: .lineLength64Characters) 
     self.sendImage(image: strBase64) 
    } 
    // perform the task asynchronously 
    group.notify(queue: asyncQueue, work: workItem) 
} 

group.wait() 

// Done!! 

EDIT: Maintenant, vous avez mis à jour votre question, je peux voir que vous faire un autre appel asynchrone. Vous pouvez gérer cela comme suit:

func sendImage(image:String, completion: @escaping() -> Void) { 

     // Your code here 

     URLSession.shared.dataTask(with: URL()) { (data, response, error) in 
      self.responseImage(data: data, response: response, error: error) 

      // When responseImage is complete, call the completion handler 
      completion() 
     } 

} 

let group = DispatchGroup() 

for image in self.arrayImages { 

    asyncQueue.async { 
     group.enter() 

     let strBase64:String = image.base64EncodedString(options: .lineLength64Characters) 
     self.sendImage(image: strBase64) { 
      group.leave() 
     } 
    } 
} 

group.wait() 

// Done!! 

Une règle simple que je veux suivre, est de toujours ajouter un gestionnaire d'achèvement en tant que paramètre à chaque async func que je vous écris.

+0

alors que dans ce cas l'id d'utilisation 'DispatchQueue.concurrentPerform' cette réponse a une valeur en montrant une approche générale –

+0

didn ' La première image est téléchargée puis la réponse à mon API échoue –

+0

J'envoie mes images sous la forme d'une chaîne de 64 octets à mon API, et je dois démarrer une discussion pour chaque requête car mon API lance une "entité de requête aussi" grande "erreur –