Ios UICollectionView cellForItemAtIndexPath在滚动时多次调用

Ios UICollectionView cellForItemAtIndexPath在滚动时多次调用,ios,swift,Ios,Swift,我有一个UICollectionView,其中每个单元格都是从Flickr异步填充的 在我的场景中,我需要21个单元格,我的代码生成的效果很好。但是,我的代码一次又一次地调用Flickr,即使在cellForItemAtIndexPath方法中填充了所有21个单元格。我查看了苹果的文档,没有看到任何地方表明滚动时应连续调用cellForItemAtIndexPath 我希望每个单元格只填充一次,然后一旦完成,就不应再次调用cellForItemAtIndexPath 这是我的密码: import

我有一个
UICollectionView
,其中每个单元格都是从Flickr异步填充的

在我的场景中,我需要21个单元格,我的代码生成的效果很好。但是,我的代码一次又一次地调用Flickr,即使在
cellForItemAtIndexPath
方法中填充了所有21个单元格。我查看了苹果的文档,没有看到任何地方表明滚动时应连续调用
cellForItemAtIndexPath

我希望每个单元格只填充一次,然后一旦完成,就不应再次调用
cellForItemAtIndexPath

这是我的密码:

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()
    }
}
导入UIKit
导入地图套件
导入CoreData
类ImagesCollectionViewController:UIViewController、UICollectionViewDataSource、UICollectionViewDelegate{
@ibvar映射视图:MKMapView!
@ibvar collectionView:UICollectionView!
var mapLat:加倍!
瓦尔·马普朗:加倍!
让flickrApi=Flickr()
var imageURLSet=[String]()
重写func viewDidLoad(){
//设置小地图的位置和缩放
设clLocation=CLLocationCoordinate2D(纬度:mapLat,经度:mapLong)
设span=MKCoordinateSpan(纬度:2,纬度:2)
setRegion(MKCoordinateRegion(中心:clLocation,span:span),动画:false)
mapView.scrollEnabled=false
getImages()
}
func collectionView(collectionView:UICollectionView,numberOfItemsInSection:Int)->Int{
返回imageURLSet.count
}
func numberOfSectionsInCollectionView(collectionView:UICollectionView)->Int{
返回1
}
func collectionView(collectionView:UICollectionView,cellForItemAtIndexPath indexPath:NSIndexPath)->UICollectionViewCell{
打印(“测试”)//在中无效
让url=NSURL(字符串:self.imageURLSet[indexPath.row])
let data=NSData(contentsofull:url!)
让img=UIImage(数据:data!)
dispatch\u async(dispatch\u get\u main\u queue(){
cell.imageView.image=img
})
}
//这是填充单元格的位置
返回单元
}
//从flickr API获取图像并存储在阵列中
func getImages(){
let参数:[String:AnyObject]=[“method”:Flickr.Consts.GEO_method,“format”:Flickr.Consts.format,“api_key”:Flickr.Consts.api_key,“lat”:mapLat,“long”:mapLong,“nojsoncallback”:“1”,“每页”:“21”,“附加内容”:“url_m”]
performGetRequest(参数){(数据,错误)在
在数据中记录为![AnyObject]{
如果(记录[“url\m”]!=nil){
打印(“记录”)
打印(将[“url\m”]记录为!字符串)
打印(“结束记录”)
self.imageURLSet.append(记录[“url\m”]as!字符串)
}
}
}
}
覆盖功能视图显示(动画:Bool){
self.collectionView.reloadData()
}
}

发生这种情况是因为UICollectionView重用单元格。每次重新调整单元格的用途时,都会调用cellForItemAtIndexPath:。显然,每次重复使用单元时进行网络呼叫并不理想

容纳单元重用和网络调用的最佳方法是实现缓存。这可以像字典一样简单,其中键是索引路径,值是Flickr图像<代码>[nsindepath:UIImage]

调用cellForRowAtIndexPath时:

1) 使用indexPath作为键检查缓存中的图像

2) 如果该键有UIImage,请在单元格中设置它

3) 如果该索引路径没有缓存的UIImage,则进行网络调用。返回时,将结果添加到缓存并更新单元格

关于代码的注释:


由于单元格是重复使用的,所以当集合视图单元格显示的对象与发起调用的对象不同时,网络调用可能会返回。您应该进行某种检查,以确保单元格当前显示的indexPath对于返回的图像是正确的。如果不这样做,可能会导致为给定数据显示错误的图像。

集合视图一次只能创建尽可能多的单元格,并在新单元格进入时重新使用已从屏幕上滚动的单元格
cellForItemAtIndexPath:
每次单元格出现在屏幕上时都会被调用。我看不到您在集合视图上调用InsertItemSatinExpaths的位置。请使用SDWebImage类下载图像,它会在下载时自动缓存图像