2017-09-16 1 views
0

J'ai du mal à télécharger une image. J'utilise une URL d'image de Firebase pour télécharger un fichier jpeg et utiliser l'image dans une légende de carte. Actuellement, la légende apparaît à la taille correcte mais sans image ni sous-titre. Cela fonctionne parfaitement lorsque je passe manuellement un élément d'image. L'URL de l'image est parfaitement enregistrée dans l'objet newDog. Quand je débogue et inspecte l'image, elle apparaît en mémoire mais semble vide.UIImage ne se charge pas après la tâche de données URLSession

Je pense que cela a peut-être quelque chose à voir avec le chargement des vues des légendes avant que le téléchargement de l'image ne soit terminé.

Voici mon viewDidLoad:

override func viewDidLoad() { 
    super.viewDidLoad() 

    self.map.mapType = .standard 
    self.map.showsUserLocation = true 
    self.map.userTrackingMode = .follow 
    self.map.delegate = self 
    self.map.mapType = .hybrid 
    let userDogRef = FIRDatabase.database().reference().child("users").child((FIRAuth.auth()?.currentUser?.uid)!).child("dogs") 

    userDogRef.observe(.childAdded, with: { (snapshot) in 
     if snapshot.value == nil { 
      print("no new dog found") 
     } else { 
      print("new dog found") 

      let snapshotValue = snapshot.value as! Dictionary<String, String> 
      let dogID = snapshotValue["dogID"]! 

      let dogRef = FIRDatabase.database().reference().child("dogs").child(dogID) 
      dogRef.observeSingleEvent(of: .value, with: { (snap) in 
       print("Found dog data!") 
       let value = snap.value as! Dictionary<String, String> 

       let name = value["name"]! 
       let breed = value["breed"]! 
       let creator = value["creator"]! 
       let score = Int(value["score"]!)! 
       let lat = Double(value["latitude"]!)! 
       let lon = Double(value["longitude"]!)! 
       let url = value["imageURL"]! 
       let location = CLLocationCoordinate2D(latitude: lat, longitude: lon) 

       let newDog = Dog() 
       newDog.name = name 
       newDog.breed = breed 
       newDog.creator = creator 
       newDog.score = score 
       newDog.imageURL = url 
       newDog.location = location 

       let downloadURL = URL(string: newDog.imageURL)! 
       URLSession.shared.dataTask(with: downloadURL, completionHandler: { (data, response, error) in 
        if error != nil { 
         print(error!) 
         return 
        } 
        newDog.picture = UIImage(data: data!)! 
        self.dogs.append(newDog) 
        let annotation = CustomAnnotation(location: newDog.location, title: newDog.name, subtitle: newDog.creator) 
        DispatchQueue.main.async { 
         self.map.addAnnotation(annotation) 
        } 

       }).resume() 
      }) 
     } 
    }) 
} 

Voici mes méthodes de MapView et d'annotation:

func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? { 
    if(annotation is MKUserLocation){ 
     return nil 
    } 

    let ident = "pin" 

    var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: ident) 
    if annotationView == nil { 
     annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: ident) 
     annotationView?.canShowCallout = true 
    } else { 
     annotationView!.annotation = annotation 
    } 
    configureDetailView(annotationView!) 
    return annotationView 
} 

func configureDetailView(_ annotationView: MKAnnotationView) { 
    let width = 300 
    let height = 300 

    let dogPhotoView = UIView() 
    let views = ["dogPhotoView": dogPhotoView] 
    dogPhotoView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:[dogPhotoView(\(height))]", options: [], metrics: nil, views: views)) 
    dogPhotoView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:[dogPhotoView(\(width))]", options: [], metrics: nil, views: views)) 


    for dog in self.dogs { 
     let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: width, height: height)) 
     imageView.image = dog.picture 
    } 

    annotationView.detailCalloutAccessoryView = dogPhotoView 
} 

J'utilise une classe d'annotation personnalisée. Voilà que:

class CustomAnnotation: NSObject, MKAnnotation { 
    var coordinate : CLLocationCoordinate2D 
    var title: String? 
    var subtitle: String? 

    init(location: CLLocationCoordinate2D, title: String, subtitle: String) { 
     self.coordinate = location 
     self.title = title 
     self.subtitle = title 
     super.init() 
    } 

    required init?(coder aDecoder: NSCoder) { 
     fatalError("init(coder:) has not been implemented") 
    } 
} 

Voici une photo de mon débogueur: enter image description here

Répondre

0

Le problème s'est produit lors de la construction de l'affichage de l'image de légende. J'ai créé un imageView, mais je ne l'ai jamais ajouté comme sous-vue de sa vue d'ensemble. Quelle erreur stupide! Voici le code correct:

func configureDetailView(_ annotationView: MKAnnotationView) { 
    let width = 300 
    let height = 300 

    let dogPhotoView = UIView() 
    let views = ["dogPhotoView": dogPhotoView] 
    dogPhotoView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:[dogPhotoView(\(height))]", options: [], metrics: nil, views: views)) 
    dogPhotoView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:[dogPhotoView(\(width))]", options: [], metrics: nil, views: views)) 


    for dog in self.dogs { 
     let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: width, height: height)) 
     imageView.image = dog.picture 

     DispatchQueue.main.async { 
      dogPhotoView.addSubview(imageView) 
      self.view.layoutIfNeeded() 
     } 

    } 

    annotationView.detailCalloutAccessoryView = dogPhotoView 
} 
0

dataTask fonctionne de manière asynchrone. Vous devez passer au code pour créer l'annotation dans le gestionnaire d'achèvement.

URLSession.shared.dataTask(with: downloadURL, completionHandler: { (data, response, error) in 
    if error != nil { 
     print(error!) 
     return 
    } 
    newDog.picture = UIImage(data: data!)! 
    self.dogs.append(newDog) 
    let annotation = CustomAnnotation(location: newDog.location, title: newDog.name, subtitle: newDog.creator) 
    DispatchQueue.main.async { 
     self.map.addAnnotation(annotation) 
    } 

}).resume() 
+0

J'ai essayé ceci, mais je reçois toujours le même résultat. S'il vous plaît jeter un oeil à mon code édité. @vadian –

+1

Ne modifiez pas le code en appliquant des suggestions. Il confond les autres qui essaient d'aider – vadian

+0

J'apprécie cela, je n'y avais pas pensé auparavant. –

0

mouvement self.map.addAnnotation(annotation) de gestionnaire d'achèvement URLSession.shared.dataTask. Actuellement, l'image est définie sur Chien après que la carte ajoute une annotation. N'oubliez pas d'ajouter l'appel addAnnotation (_ :) avec OperationQueue.main.addOperation.