我有一个 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/