2015-03-17 1 views
0

J'utilise l'API Google image pour générer des images comme celle-ci:NSURLConnection dans Swift: Comment appeler une fonction quand le chargement est terminé, et redémarrer si l'URL est un 404?

let url = NSURL(string: "https://ajax.googleapis.com/ajax/services/search/images?v=1.0&q=seattle") 
let request = NSURLRequest(URL: url!) 
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()){ (response, go, error) -> Void in    
let go = NSJSONSerialization.JSONObjectWithData(go, options: NSJSONReadingOptions.AllowFragments, error: nil) as [String:AnyObject] 
let responseData = go["responseData"] as [String:AnyObject] 

Puis le reste de déterre le code vers le bas pour trouver l'URL de l'image google api donne et ensembles (var Theurl ici) l'image dans l'application que:

let data = NSData(contentsOfURL: theurl!) 
self.mainImage.image = UIImage(data: data!) 

Cela fonctionne, mais j'ai besoin 1) pour arrêter le processus et appeler une fonction si elle trouve une URL de l'image qu'il ne peut pas charger et 2) appeler une fonction lorsque l'image a terminé le chargement.

Répondre

3

Vous avez quelques problèmes ici à résoudre. Je pense qu'il serait plus logique de suivre un exemple. Ce qui suit est exactement la même logique, juste un peu plus robuste.

import UIKit 

class ImageViewController: UIViewController { 
    var mainImage: UIImageView! 
    let operationQueue: NSOperationQueue = { 
     let queue = NSOperationQueue() 
     queue.maxConcurrentOperationCount = 4 
     queue.qualityOfService = NSQualityOfService.Utility 

     return queue 
    }() 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     downloadImage { [weak self] image in 
      if let strongSelf = self { 
       if let image = image { 
        strongSelf.mainImage.image = image 
       } 
      } 
     } 
    } 

    func downloadImage(completion: UIImage? -> Void) { 
     let url = NSURL(string: "https://ajax.googleapis.com/ajax/services/search/images?v=1.0&q=seattle") 
     let request = NSURLRequest(URL: url!) 

     NSURLConnection.sendAsynchronousRequest(request, queue: self.operationQueue) { [weak self] response, data, error in 
      if let strongSelf = self { 
       if error != nil || data == nil { 
        println(error) // failed to complete original google api request 
        completion(nil) 
        return 
       } 

       var serializationError: NSError? 
       if let go = NSJSONSerialization.JSONObjectWithData(data!, options: .AllowFragments, error: &serializationError) as? [String: AnyObject] { 
        let responseData = go["responseData"] as [String:AnyObject] 
        let imageURL = NSURL(string: "some_image_url_from_response_data")! // placeholder 
        let imageRequest = NSURLRequest(URL: url!) 

        NSURLConnection.sendAsynchronousRequest(imageRequest, queue: strongSelf.operationQueue) { response, data, error in 
         if error != nil || data == nil { 
          println(error) // failed to download the image 
          completion(nil) 
          return 
         } 

         if let image = UIImage(data: data!) { 
          completion(image) 
         } else { 
          println("Failed to create UIImage from downloaded image data") 
          completion(nil) 
         } 
        } 
       } else { 
        println(serializationError) 
        completion(nil) 
       } 
      } 
     } 
    } 
} 

Fonctionnement asynchrone Queue

Tout d'abord, vous faites une demande asynchrone sur la file d'attente principale qui contrecarre le but de tout comportement async. Au lieu de cela, j'ai créé une propriété de file d'attente d'opération simultanée qui est utilisée pour gérer les opérations de téléchargement.

Weakify/Strongify

Chaque fois que vous faites des choses asynchrones, vous devez faire très attention à conserver self. Le moyen le plus sûr de vous garantir de toujours le faire correctement est de le fragiliser/renforcer pour éviter de créer un cycle de conservation.

Nested Async Demande

Vous devez utiliser un autre appel sendAsynchronousRequest pour télécharger l'image en arrière-plan. Sinon, vous allez bloquer le thread principal pendant que vous téléchargez l'image. Vos utilisateurs ne seraient pas heureux avec ce comportement!

Safe Désérialisation

Il est assez important de vérifier que votre analyse JSON est réussie. Les serveurs peuvent parfois faire des choses étranges, et votre code devrait être capable de gérer cela sans problème.

Alamofire

Avez-vous pris un coup d'œil à Alamofire? Cela facilite beaucoup les choses comme ça.

Espérons que cela aide à éclaircir.

+0

merci, je vais passer en revue cela. Je viens de commencer à apprendre sur les API et swift/JSON. – ZhouW

1

Utilisez le bloc d'achèvement et vérifiez le NSError que vous obtenez.

NSURLConnection.sendAsynchronousRequest(request, queue: queue, completionHandler:{ (response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in 
    if let theError = error{ 
     if theError.code == 404{ 
     //Image not available 
     }else{ 
     //something else 
     } 
    } 
}) 
+0

Puis-je copier et coller cela tout en conservant mon original "NSURLConnection.sendAsynchronousRequest (request, queue: NSOperationQueue.mainQueue()) {(réponse, go, error) -> Void dans" line? Aussi avec la file d'attente: file d'attente j'obtiens une erreur "utilisation de l'identificateur de file d'attente non résolue", devrais-je mettre "var file: NSOperationQueue = NSOperationQueue()" en haut puis faire la queue: self.queue? – ZhouW

+0

Ceci est un exemple de code. Vous devez l'éditer pour que cela fonctionne pour vous. Mais vous devez utiliser cela à la place de votre méthode. – Christian

+0

Notez que cela va planter si aucune erreur ne se produit puisque l'erreur sera nulle. –