2016-06-24 35 views
1

Ich habe diesen nervigen Fehler in meiner App, dass jedes Mal, wenn ich den UICollectionView-Controller lade, er die Zellen dupliziert.Swift 2 reloadData fügt dem UICollectionView weitere Zellen hinzu

Das ist also die, wenn die Sammlung Ansicht lädt zum ersten Mal: ​​

enter image description here

Ich habe 2 View-Controller so ist dies der zweite View-Controller ist. Wenn ich an den ersten View-Controller abschalten zurück, die nur 1 Taste zum 2. View-Controller hat und segue wieder in den zweiten View-Controller, der die reload Funktion auslöst, geschieht dies:

enter image description here

Ich bin nicht wirklich sicher, warum das passiert, ich verwende Todd Kramer's UICollectionView mit zwischengespeicherten Bildern: http://www.tekramer.com/downloading-images-asynchronously-in-swift-with-alamofire/ Der einzige Unterschied ist, dass ich die Bild URLs und Daten von JSON asynchron laden, anstatt statisch in einem Modell oder Plist wie das Tutorial zu definieren.

Hier sind die Klassen mit Änderungen, die ich im Code gemacht:

import UIKit 
import SwiftyJSON 

private let PhotoCollectionViewCellIdentifier = "cell" 

class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource { 

@IBOutlet weak var collectionView: UICollectionView! 

var index: NSIndexPath! 

var names = [String]() 
var imgsUrl = [String]() 

override func viewDidLoad() { 
    super.viewDidLoad() 
    // Do any additional setup after loading the view, typically from a nib. 

    let photo = PhotosDataManager() 
    let api = Api() 

    api.loadJsonData(self.names, imgsUrl: self.imgsUrl, batch: "2016", dept: "dafa") { names, imgsUrl in 
     self.names = names 
     self.imgsUrl = imgsUrl 
     photo.allPhotos(self.names, imgUrls: self.imgsUrl) 
     self.collectionView.reloadData() 
    } 
} 

@IBAction func button(sender: UIButton) { 
    NSNotificationCenter.defaultCenter().postNotificationName("alert1", object: self, userInfo: nil) 
} 

func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 

    return PhotosDataManager.sharedManager.allPhotos(self.names, imgUrls: self.imgsUrl).count 
} 

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell { 

    let cell = collectionView.dequeueReusableCellWithReuseIdentifier(PhotoCollectionViewCellIdentifier, forIndexPath: indexPath) as! CollectionViewCell 
    dispatch_async(dispatch_get_main_queue(), { 
     cell.configure(self.glacierScenicAtIndex(indexPath)) 
    }) 

    return cell 
} 

func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) { 
    PhotosDataManager.sharedManager.purgeCache() 
    self.performSegueWithIdentifier("previousViewController", sender: self) 

} 

func glacierScenicAtIndex(indexPath: NSIndexPath) -> GlacierScenic { 
    let photos = PhotosDataManager.sharedManager.allPhotos(self.names, imgUrls: self.imgsUrl) 
    return photos[indexPath.row] 
} 

} 

class PhotosDataManager { 

static let sharedManager = PhotosDataManager() 
private var photos = [GlacierScenic]() 

let decoder = ImageDecoder() 
let photoCache = AutoPurgingImageCache(
    memoryCapacity: 100 * 1024 * 1024, 
    preferredMemoryUsageAfterPurge: 60 * 1024 * 1024 
) 

func allPhotos(names: [String], imgUrls: [String]) -> [GlacierScenic] { 

    var glacierScenic: GlacierScenic! 

    for i in 0 ..< names.count { 
     glacierScenic = GlacierScenic(name: names[i], photoURLString: imgUrls[i]) 
     photos.append(glacierScenic) 
    } 

    return photos 
} 

func getNetworkImage(urlString: String, completion: (UIImage -> Void)) -> (ImageRequest) { 
    let queue = decoder.queue.underlyingQueue 
    let request = Alamofire.request(.GET, urlString) 
    let imageRequest = ImageRequest(request: request) 
    imageRequest.request.response(
     queue: queue, 
     responseSerializer: Request.imageResponseSerializer(), 
     completionHandler: { response in 
      guard let image = response.result.value else { 
       return 
      } 
      let decodeOperation = self.decodeImage(image) { image in 
       completion(image) 
       self.cacheImage(image, urlString: urlString) 
      } 
      imageRequest.decodeOperation = decodeOperation 
     } 
    ) 
    return imageRequest 
} 

func decodeImage(image: UIImage, completion: (UIImage -> Void)) -> DecodeOperation { 
    let decodeOperation = DecodeOperation(image: image, decoder: self.decoder, completion: completion) 
    self.decoder.queue.addOperation(decodeOperation) 
    return decodeOperation 
} 

func cacheImage(image: Image, urlString: String) { 
    photoCache.addImage(image, withIdentifier: urlString) 
} 

func cachedImage(urlString: String) -> Image? { 
    return photoCache.imageWithIdentifier(urlString) 
} 

func purgeCache() { 
//  photoCache.removeAllImages() 
    print("memory used: \(photoCache.memoryUsage)") 
} 

} 

class PhotosDataManager { 

static let sharedManager = PhotosDataManager() 
private var photos = [GlacierScenic]() 

let decoder = ImageDecoder() 
let photoCache = AutoPurgingImageCache(
    memoryCapacity: 100 * 1024 * 1024, 
    preferredMemoryUsageAfterPurge: 60 * 1024 * 1024 
) 

func allPhotos(names: [String], imgUrls: [String]) -> [GlacierScenic] { 

    var glacierScenic: GlacierScenic! 

    for i in 0 ..< names.count { 
     glacierScenic = GlacierScenic(name: names[i], photoURLString: imgUrls[i]) 
     photos.append(glacierScenic) 
    } 

    return photos 
} 

func getNetworkImage(urlString: String, completion: (UIImage -> Void)) -> (ImageRequest) { 
    let queue = decoder.queue.underlyingQueue 
    let request = Alamofire.request(.GET, urlString) 
    let imageRequest = ImageRequest(request: request) 
    imageRequest.request.response(
     queue: queue, 
     responseSerializer: Request.imageResponseSerializer(), 
     completionHandler: { response in 
      guard let image = response.result.value else { 
       return 
      } 
      let decodeOperation = self.decodeImage(image) { image in 
       completion(image) 
       self.cacheImage(image, urlString: urlString) 
      } 
      imageRequest.decodeOperation = decodeOperation 
     } 
    ) 
    return imageRequest 
} 

func decodeImage(image: UIImage, completion: (UIImage -> Void)) -> DecodeOperation { 
    let decodeOperation = DecodeOperation(image: image, decoder: self.decoder, completion: completion) 
    self.decoder.queue.addOperation(decodeOperation) 
    return decodeOperation 
} 

func cacheImage(image: Image, urlString: String) { 
    photoCache.addImage(image, withIdentifier: urlString) 
} 

func cachedImage(urlString: String) -> Image? { 
    return photoCache.imageWithIdentifier(urlString) 
} 

func purgeCache() { 
//  photoCache.removeAllImages() 
    print("memory used: \(photoCache.memoryUsage)") 
} 

} 
+0

in den allphotos Funktion, die Sie for-Schleife verwenden, die gleichen Daten immer wieder anhängen. –

Antwort

2

AUSGABE

In PhotosDataManager => Sie verwenden die sharedManager-Referenz, die die Objektreferenz in der statischen Referenz speichert und sie in allen Segues-Navigation wiederverwendet, und somit Ihre allPhotos-Methode, fügen Sie weiterhin Daten im alten Array hinzu.

static let sharedManager = PhotosDataManager() 

ANOTHER AUSGABE

Rufen Sie nicht allphotos Methode in numberOfItemsInSection, da es mehrere Anzahl, wie oft aufgerufen wird, was möglicherweise die Daten mehrere Anzahl, wie oft anhängen


LÖSUNG

In Ihrer Methode:

func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 

    //USE Instantiated reference 
    return photos.getPhotosCount() 
} 

Stattdessen in Ihrer Klasse Klasse PhotosDataManager

class PhotosDataManager { 

    func getPhotosCount(){ 

    return photos.count 
    } 
} 
+0

Es funktioniert bei der Rückgabe von allPhotos.count aber nicht mit getPhotosCount. – Renboy

+0

Ok, es funktioniert jetzt, als ich allPhotos anrief, bevor ich getPhotosCount zurückgab. Vielen Dank. – Renboy

+0

Kann ich noch eine Frage haben, ob es in Ordnung ist? – Renboy