2016-05-11 13 views
1

Ich habe eine UICollectionView in der jede Zelle asynchron von Flickr bestückt ist.UICollectionView cellForItemAtIndexPath rief immer und immer wieder auf Scrollen

In meiner Szene möchte ich 21 Zellen, mein Code produziert das ganz gut. Mein Code ruft Flickr jedoch immer wieder auf, auch nachdem alle 21 Zellen in der cellForItemAtIndexPath-Methode aufgefüllt wurden. Ich sehe mir die Apple-Dokumente an und habe nirgendwo gesehen, dass cellForItemAtIndexPath ständig beim Scrollen aufgerufen werden sollte.

Ich mag jede Zelle nur einmal gefüllt werden und dann einmal abgeschlossen cellForItemAtIndexPath soll nicht wieder aufgerufen werden.

Hier ist mein Code:

import UIKit 
import MapKit 
import CoreData 

class ImagesCollectionViewController : UIViewController, UICollectionViewDataSource, UICollectionViewDelegate{ 

    @IBOutlet weak var mapView: MKMapView! 

    @IBOutlet weak var collectionView: UICollectionView! 
    var mapLat : Double! 
    var mapLong : Double! 
    let flickrApi = Flickr() 
    var imageURLSet = [String]() 

    override func viewDidLoad() { 

     // set the location and zoom of the minimap 
     let clLocation = CLLocationCoordinate2D(latitude: mapLat, longitude: mapLong) 
     let span = MKCoordinateSpan(latitudeDelta: 2, longitudeDelta: 2) 

     mapView.setRegion(MKCoordinateRegion(center: clLocation, span: span), animated: false) 
     mapView.scrollEnabled = false 

     getImages() 
    } 

    func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 
     return imageURLSet.count 
    } 

    func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int { 
     return 1 
    } 

    func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell { 
     print("test") // <--- this prints over and over again on scrolling 
     let cell = collectionView.dequeueReusableCellWithReuseIdentifier("ImageCell", forIndexPath: indexPath) as! FlickrImageCellViewController 
     let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) 
     dispatch_async(queue) {() -> Void in 
      let url = NSURL(string: self.imageURLSet[indexPath.row]) 
      let data = NSData(contentsOfURL: url!) 
      let img = UIImage(data: data!) 

      dispatch_async(dispatch_get_main_queue(), { 
       cell.imageView.image = img 
      }) 


     } 

     // This is where the cells are being populated 


     return cell 
    } 

    //Get images from the flickr API and store in array 

    func getImages(){ 

     let parameters : [String : AnyObject] = ["method": Flickr.Consts.GEO_METHOD, "format" : Flickr.Consts.FORMAT, "api_key": Flickr.Consts.API_KEY, "lat" : mapLat, "long" : mapLong, "nojsoncallback" : "1", "per_page" : "21", "extras" : "url_m"] 

     flickrApi.performGetRequest(parameters) { (data, error) in 


      for record in data as! [AnyObject]{ 
       if(record["url_m"] != nil){ 
        print("record") 
        print(record["url_m"] as! String) 
        print("end record") 
        self.imageURLSet.append(record["url_m"] as! String) 

       } 
      } 
     } 
    } 

    override func viewDidAppear(animated: Bool) { 

     self.collectionView.reloadData() 
    } 
} 
+3

Die Sammlung Ansicht erzeugt nur so viele Zellen wie auf dem Bildschirm auf einmal passen und verwendet die Zellen, den Bildschirm gescrollt hat als neue zu kommen 'cellForItemAtIndexPath.' Wird jedes Mal, wenn eine Zelle auf dem Bildschirm kommt aufgerufen. – dan

+0

Ich sehe nicht, wo Sie insertItemsAtIndexPaths in Ihrer Sammlungsansicht aufrufen. –

Antwort

2

Dies geschieht, weil die UICollectionView Zellen wiederverwendet. Jedes Mal, wenn eine Zelle neu zugewiesen wird, wird cellForItemAtIndexPath: aufgerufen. Offensichtlich ist es nicht ideal, bei jeder Wiederverwendung einer Zelle einen Netzwerkanruf zu tätigen.

Der beste Weg, Zelle Wiederverwendung und Netzwerk-Anrufe aufzunehmen ist ein Cache zu implementieren. Dies kann etwas so einfaches wie ein Wörterbuch sein, bei dem die Schlüssel Ihre Indexpfade sind und die Werte Ihre Flickr-Bilder sind. [NSIndexPath: UIImage]

Wenn cellForRowAtIndexPath heißt:

1) für ein Bild Cache Überprüfen Sie die indexPath als Schlüssel.

2) Wenn es eine UIImage für diesen Schlüssel ist, setzen Sie ihn in der Zelle.

3) Wenn es keine cached UIImage für diesen Index Pfad ist, das Netzwerk Anruf. Wenn es zurückgegeben wird, fügen Sie die Ergebnisse Ihrem Cache hinzu und aktualisieren Sie die Zelle.

Ein Hinweis auf dem Code:

Da Zellen wiederverwendet werden, ist es möglich, Ihr Netzanruf zu einer Zeit, Zelle Ihrer Sammlung Ansicht zurückkehren wird ein anderes Objekt als die Anzeige, für die der Anruf initiiert wurde. Sie sollten überprüfen, ob der aktuell von der Zelle angezeigte IndexPfad der richtige für das zurückgegebene Bild ist. Wenn Sie dies nicht tun, können Sie das falsche Bild für Ihre Daten anzeigen.

+0

Verwenden Sie die SDWebImage-Klasse zum Herunterladen des Bilds, das das Bild beim Herunterladen automatisch zwischenspeichert –

Verwandte Themen