ios - UICollectionView cellForItemAtIndexPath 在滚动时一遍又一遍地调用

原文 标签 ios swift

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

在我的场景中,我想要 21 个单元格,我的代码可以很好地生成它。但是,即使在 cellForItemAtIndexPath 中填充了所有 21 个单元格之后,我的代码仍会一次又一次地调用 Flickr。方法。我查看了 Apple 文档,但没有看到任何说明 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()
    }
}

最佳答案

这是因为 UICollectionView 重用了单元格。每次单元格被重新利用时,都会调用 cellForItemAtIndexPath: 。显然,每次重用小区时都进行一次网络调用并不理想。

适应单元重用和网络调用的最佳方法是实现缓存。这可以像字典一样简单,其中键是您的索引路径,值是您的 Flickr 图像。 [NSIndexPath: UIImage]
当 cellForRowAtIndexPath 被调用时:

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

2) 如果该键有 UIImage,请将其设置在您的单元格中。

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

关于您的代码的注释:

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

关于ios - UICollectionView cellForItemAtIndexPath 在滚动时一遍又一遍地调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37169087/

相关文章:

ios - 在这里iOS SDK:Places API make * Request始终返回nil

ios - UIAlertView 上的按钮

ios - 无法调用ScheduledTimer

ios - 为 performSegueWithIdentifier() 设置 Storyboard

c# - 使用.net http2的Apple Push Notification

ios - 如何为 siri 快捷方式的每个自定义意图使用不同的 View Controller ?

ios - 无法使用 Objective-C 调用电话号码

ios - 适用于iOS 9.0的AVCaptureDevice DiscoverySession

swift - 如何在快速游乐场中读取文件

ios - Xcode 6 Swift WKWebView键盘设置