2015-11-12 9 views
8

Das Problem Laden:Collection Zelle duplizieren, wenn mehr Daten

ich eine Collection haben, die eine UIImage in jede Zelle lädt. Mein Problem ist jedoch, dass wenn ich zusätzliche Zellen mit mehr Bildern lade, sie zu duplizieren scheinen. Ich kann nicht genau sehen, was das in meinem Code verursachen könnte. Könnte es wegen eines Problems mit wiederverwendbaren Zellen sein?

Kann jemand sehen, warum dies vorkommt?

HINWEIS: Das Array mit den Bildern haben keine Duplikate

Video des Problems: https://www.youtube.com/watch?v=vjRsFc8DDmI

Bild des Problems:

CollectionView has duplicate cell when loading more data

Hier sind meine Funktionen für Kollektion:

func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 
    //#warning Incomplete method implementation -- Return the number of items in the section 
    if self.movies == nil 
    { 
     return 0 

    } 

    return self.movies!.count 

} 

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell 
{ 
    let cell =  
     collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, 
     forIndexPath: indexPath) as! UpcomingCollectionViewCell 

    if self.movies != nil && self.movies!.count >= indexPath.row 
    { 
     // Calc size of cell 
     cell.frame.size.width = screenWidth/3 
     cell.frame.size.height = screenWidth/3 * 1.54 

     let movies = self.movies![indexPath.row] 
     if(movies.posterPath != "" || movies.posterPath != "null"){ 
     cell.data = movies.posterPath 
     } 
     else{ 
     cell.data = nil 
     } 
     // See if we need to load more movies 
     let rowsToLoadFromBottom = 5; 
     let rowsLoaded = self.movies!.count 
     if (!self.isLoadingMovies && (indexPath.row >= (rowsLoaded - rowsToLoadFromBottom))) 
     { 
      let totalRows = self.movieWrapper!.totalResults! 
      let remainingMoviesToLoad = totalRows - rowsLoaded; 
      if (remainingMoviesToLoad > 0) 
      { 
       self.loadMoreMovies() 
      } 
     } 
} 
    else 
{ 
     cell.data = nil 
} 

    return cell 
} 

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize 
{ 
    return CGSize(width: screenWidth/3, height: screenWidth/3*1.54) 
} 

Hier lade ich die Daten aus einer Wrapper-Klasse:

func loadFirstMovies() 
{ 

    isLoadingMovies = true 

    Movies.getMovies({ (movieWrapper, error) in 
     if error != nil 
     { 
      // TODO: improved error handling 
      self.isLoadingMovies = false 
      let alert = UIAlertController(title: "Error", message: "Could not load first movies \(error?.localizedDescription)", preferredStyle: UIAlertControllerStyle.Alert) 
      alert.addAction(UIAlertAction(title: "Click", style: UIAlertActionStyle.Default, handler: nil)) 
      self.presentViewController(alert, animated: true, completion: nil) 
     } 
     self.addMoviesFromWrapper(movieWrapper) 
     self.activityIndicator.hidden = true 
     self.isLoadingMovies = false 
     self.collectionView.reloadData() 
    }) 
} 

func loadMoreMovies(){ 

    self.isLoadingMovies = true 
    if self.movies != nil && self.movieWrapper != nil && self.movieWrapper!.page < self.movieWrapper!.totalPages 
    { 
     // there are more species out there! 
     Movies.getMoreMovies(self.movieWrapper, completionHandler: { (moreWrapper, error) in 
      if error != nil 
      { 
       // TODO: improved error handling 
       self.isLoadingMovies = false 
       let alert = UIAlertController(title: "Error", message: "Could not load more movies \(error?.localizedDescription)", preferredStyle: UIAlertControllerStyle.Alert) 
       alert.addAction(UIAlertAction(title: "Click", style: UIAlertActionStyle.Default, handler: nil)) 
       self.presentViewController(alert, animated: true, completion: nil) 
      } 
      print("got more!") 
      self.addMoviesFromWrapper(moreWrapper) 
      self.isLoadingMovies = false 
      self.collectionView.reloadData() 
     }) 
    } 
} 

func addMoviesFromWrapper(wrapper: MovieWrapper?) 
{ 
    self.movieWrapper = wrapper 
    if self.movies == nil 
    { 
     self.movies = self.movieWrapper?.results 
    } 
    else if self.movieWrapper != nil && self.movieWrapper!.results != nil 
    { 
     self.movies = self.movies! + self.movieWrapper!.results! 
    } 
} 

Und schließlich nenne ich: loadFirstMovies() in viewDidLoad()

EDIT: Die folgendeCollectionViewCell

class UpcomingCollectionViewCell: UICollectionViewCell { 

@IBOutlet weak var imageView: UIImageView! 


var data:String?{ 
    didSet{ 
     self.setupData() 
    } 
} 

func setupData(){ 

    self.imageView.image = nil // reset the image 

    if let urlString = data{ 
     let url = NSURL(string: "http://image.tmdb.org/t/p/w342/" + urlString) 
     self.imageView.hnk_setImageFromURL(url!) 


     } 
    } 
} 
+0

zeigen Sie den Code Ihrer 'UpcomingCollectionViewCell' ... –

+0

Ich habe die Frage mit UpcomingCollectionViewCell aktualisiert – Mat0

Antwort

12

Dies ist ein typisches Setup-Problem bei der Tabellenansicht/Sammlungsansicht.

Jedes Mal, wenn Sie eine Zelle mit einer Entnahmemethode wie dequeueReusableCellWithReuseIdentifier: recyceln, müssen Sie alle Ansichten in der Zelle immer vollständig konfigurieren, einschließlich der Einstellung aller Textfelder/Bildansichten auf ihre Startwerte. Ihr Code enthält mehrere if-Anweisungen, bei denen die Bedingung für if falsch ist und Sie die Ansichten in der Zelle nicht einrichten. Sie müssen else-Klauseln haben, die den alten Inhalt aus den Ansichten der Zelle löschen, wenn vom letzten Zeitpunkt der Verwendung der Zelle noch Inhalte übrig sind.

** EDIT:

ändern cellForItemAtIndexPath Methode wie folgt beginnen:

func collectionView(collectionView: UICollectionView, 
    cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell 
{ 
    let cell =  
     collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, 
     forIndexPath: indexPath) as! UpcomingCollectionViewCell 
    cell.imageView.image = nil; //Remove the image from the recycled cell 
//The rest of your method ... 
+0

Ich habe die Antwort bearbeitet mit else-Anweisungen in "cellForItemAtIndexPath" Es führt immer noch dazu, dass einige Zellen dupliziert werden. Aber passiert nicht so oft im Vergleich zu vorher (ohne sonst)? – Mat0

+0

Um diese Arbeit zu machen, müsste André Slotta auch zu setupData wechseln (wo Sie das imageView-Bild vor dem Laden eines neuen Bildes auf null setzen).) –

+0

Ich habe "André Slottas" Änderung hinzugefügt, aber Zellen sind jetzt leer und nicht mit einem neuen Bild geladen. Ich habe ein kurzes Video von seinem aktuellen Stand gemacht, siehe: https://www.youtube.com/watch?v=vjRsFc8DDmI. Der Code wird auch aktualisiert – Mat0

2

in Ihrer benutzerdefinierten Zellen setupData() Methode versuchen Sie folgendes:

func setupData(){ 
    self.imageView.image = nil // reset the image 

    if let urlString = data{ 
    let url = NSURL(string: "http://image.tmdb.org/t/p/w342/" + urlString) 
    self.imageView.hnk_setImageFromURL(url!) 
    } 
} 
+0

Dies löscht das Bild der Zellen, führt aber dazu, dass einige Zellen leer sind. – Mat0

+0

naja ... wenn es einen 'urlString' gibt, der zu einer tatsächlichen Bilddatei führt und die' hnk_setImageFromURL' Methode wie erwartet funktioniert, sollte dieser Code definitiv funktionieren. –

+0

hnk_setImageFromURL ist von der "Haneke" -Bibliothek, also erwarte ich, dass das funktioniert und URLString führt auch zu einer tatsächlichen Image-Datei? – Mat0