我正在使用Swift将图像加载到UICollectionView中。我正在异步获取图像。虽然UI在滚动时没有锁定,但还是存在一些问题。我遇到了一些重复的问题,并且它们加载到视图中相当缓慢。我创建了一个视频来准确展示这个问题:
https://www.youtube.com/watch?v=nQmAXpbrv1w&feature=youtu.be
我的代码主要参考了这个问题的被接受答案:在Swift上从URL加载/下载图像。
以下是我的完整代码。
在我的UICollectionViewController类声明之下,我声明了一个变量:
let API = APIGet()
在UICollectionViewController的viewDidLoad中,我调用:
override func viewDidLoad() {
API.getRequest()
API.delegate = self
}
在我的APIGet类中,我有一个函数叫做getRequest:
func getRequest() {
let string = "https://api.imgur.com/3/gallery/t/cats"
let url = NSURL(string: string)
let request = NSMutableURLRequest(URL: url!)
request.setValue("Client-ID \(cliendID)", forHTTPHeaderField: "Authorization")
let session = NSURLSession.sharedSession()
let tache = session.dataTaskWithRequest(request) { (data, response, error) -> Void in
if let antwort = response as? NSHTTPURLResponse {
let code = antwort.statusCode
print(code)
do {
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers)
dispatch_async(dispatch_get_main_queue(), { () -> Void in
if let data = json["data"] as? NSDictionary {
if let items = data["items"] as? NSArray {
var x = 0
while x < items.count {
if let url2 = items[x]["link"] {
self.urls.append(url2! as! String)
}
x++
}
self.delegate?.retrievedUrls(self.urls)
}
}
})
}
catch {
}
}
}
tache.resume()
}
上述函数正好完成了它应该做的事情:从端点获取JSON,并从JSON中获取图像的URL。一旦检索到所有URL,它就将它们传回UICollectionViewController。
现在,对于我的UICOllectionViewController中的代码。这是从APIGet类接收URL的函数。
func retrievedUrls(x: [String]) {
//
self.URLs = x
var y = 0
while y < self.URLs.count {
if let checkedURL = NSURL(string: self.URLs[y]) {
z = y
downloadImage(checkedURL)
}
y++
}
}
然后,这两个函数负责下载图像:
func getDataFromUrl(url:NSURL, completion: ((data: NSData?, response: NSURLResponse?, error: NSError? ) -> Void)) {
NSURLSession.sharedSession().dataTaskWithURL(url) { (data, response, error) in
completion(data: data, response: response, error: error)
}.resume()
}
func downloadImage(url: NSURL){
getDataFromUrl(url) { (data, response, error) in
dispatch_async(dispatch_get_main_queue()) { () -> Void in
guard let data = data where error == nil else { return }
if let image = UIImage(data: data) {
self.images.append(image)
self.collectionView?.reloadData()
}
}
}
}
当图片加载完成后,如果我调用self.collectionView.reloadData(),则每次加载新图片时,集合视图会闪烁并且单元格会移动。但是,如果我根本不调用self.collectionView.reloadData(),那么在图片加载完成后,集合视图永远不会重新加载,单元格保持为空。我该怎么解决这个问题?我希望图片直接加载到它们各自的单元格中,而不会导致集合视图闪烁/闪光或单元格移动,也不会出现临时重复。
我的cellForRowAtIndexPath方法很简单:
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("cell1", forIndexPath: indexPath) as! cell1
if indexPath.row > (images.count - 1) {
cell.image.backgroundColor = UIColor.grayColor()
}
else {
cell.image.image = images[indexPath.row]
}
return cell
}
这是我第一次尝试在iOS中进行网络编程,因此我不想使用库(如alamofire、AFNetworking、SDWebImage等),以便从基础开始学习。谢谢您阅读所有内容!
编辑:以下是我的最终代码,大部分取自下面的答案:
func retrievedUrls(x: [String]) {
//
self.URLs = x
self.collectionView?.reloadData()
var y = 0
while y < self.URLs.count {
if let checkedURL = NSURL(string: self.URLs[y]) {
downloadImage(checkedURL, completion: { (image) -> Void in
})
}
y++
}
}
func getDataFromUrl(url:NSURL, completion: ((data: NSData?, response: NSURLResponse?, error: NSError? ) -> Void)) {
NSURLSession.sharedSession().dataTaskWithURL(url) { (data, response, error) in
completion(data: data, response: response, error: error)
}.resume()
}
func downloadImage(url: NSURL, completion: (UIImage) -> Void) {
getDataFromUrl(url) { (data, response, error) -> Void in
dispatch_async(dispatch_get_main_queue()) { () -> Void in
guard let data = data where error == nil else { return }
if let image = UIImage(data: data) {
self.images.append(image)
let index = self.images.indexOf(image)
let indexPath = NSIndexPath(forRow: index!, inSection: 0)
self.collectionView?.reloadItemsAtIndexPaths([indexPath])
}
}
}
}
我的 cellForItemAtIndexPath 没有改变。
y
,然后编写while y < self.URLs.count { // ... }
,而是尝试使用for url in self.URLs
。这样做的好处是你不再需要处理索引了,并且你可以立即获得所需的对象,而无需再次使用该索引。 - Alex Popov