Я новичок в программировании быстрого и iOS, но мне удалось создать в основном стабильный интерфейс для моего приложения в Xcode. CollectionView захватывает изображение и текст из массива словарей, созданных из файла csv на моем домашнем сетевом сервере. Файл резюме содержит данные в следующем формате (примечание, адреса были изменены, чтобы защитить лицензионные изображения):swift iOS - UICollectionView изображения смешались после быстрого прокрутки
CSV файл
csv file is @ url https://myserver.com/csv.txt and contains the following
Title";"SeriesImageURL
Title1";"https://licensedimage.com/url1
Title2";"https://licensedimage.com/url2
...
Title1000";"https://licensedimage.com/url1000
Проблема заключается в том, что при быстром пролистывании CollectionView, клетка захватит неправильное изображение. Заметно, что если вы выполняете медленный или средний прокрутки, другое изображение будет отображаться до того, как правильное изображение будет отображено в правильную ячейку (текст ярлыков для ячеек всегда правильный, только изображение всегда выключено). После несоответствия изображений правильной ячейке с меткой все остальные ячейки в CollectionView также будут отображаться неправильно.
E.g. В ячейке 1-9 будет отображаться Title1-9 с правильным изображением1-9 При медленной прокрутке, ячейки 19-27 будут отображать заголовок 19-27, на короткое время отобразится изображение 10-18, а затем отобразится правильное изображение 19-27. При быстром прокрутке огромного количества ячеек (например, от ячейки 1-9 до ячейки 90-99), ячейки 90-99 будут отображать заголовок 90-99, будет отображаться изображение 10-50ish, а затем будет неправильно оставаться на изображении 41- 50 (или около того). При дальнейшем прокрутке ячейки 100+ будут отображать правильное название, но будут отображаться только изображения из диапазона изображения 41-50.
Я думаю, что эта ошибка возникает либо из-за неправильного обращения с использованием ячеек, а к кешированию изображений, которые не обрабатываются должным образом, или того и другого. Это может быть и то, что я не вижу как начинающий программист iOS/swift. Я попытался реализовать запрос с модификатором завершения, но не могу заставить его работать должным образом с тем, как настроен мой код. Я был бы признателен за любую помощь в этом, а также за объяснение того, почему исправление работает так, как оно есть. Благодаря!
Соответствующий код приведен ниже.
SeriesCollectionViewController.swift
class SeriesCollectionViewController: UICollectionViewController, UISearchBarDelegate {
let reuseIdentifier:String = "SeriesCell"
// Set Data Source Models & Variables
struct seriesModel {
let title: AnyObject
let seriesimageurl: AnyObject
}
var seriesDict = [String:AnyObject]()
var seriesArray = [seriesModel]()
// Image Cache
var imageCache = NSCache()
override func viewDidLoad() {
super.viewDidLoad()
// Grab Data from Source
do {
let url = NSURL(string: "https://myserver.com/csv.txt")
let fullText = try NSString(contentsOfURL: url!, encoding: NSUTF8StringEncoding)
let readings = fullText.componentsSeparatedByString("\n") as [String]
var seriesDictCount = readings.count
seriesDictCount -= 1
for i in 1..<seriesDictCount {
let seriesData = readings[i].componentsSeparatedByString("\";\"")
seriesDict["Title"] = "\(seriesData[0])"
seriesDict["SeriesImageURL"] = "\(seriesData[1])"
seriesArray.append(seriesModel(
title: seriesDict["Title"]!,
seriesimageurl: seriesDict["SeriesImageURL"]!,
))
}
} catch let error as NSError {
print("Error: \(error)")
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
imageCache.removeAllObjects()
// Dispose of any resources that can be recreated.
}
//...
//...skipping over some stuff that isn't relevant
//...
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> SeriesCollectionViewCell {
let cell: SeriesCollectionViewCell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as! SeriesCollectionViewCell
if (self.searchBarActive) {
let series = seriesArrayForSearchResult[indexPath.row]
do {
// set image
if let imageURL = NSURL(string: "\(series.seriesimageurl)") {
if let image = imageCache.objectForKey(imageURL) as? UIImage {
cell.seriesImage.image = image
} else {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), {
if let tvimageData = NSData(contentsOfURL: imageURL) {
let image = UIImage(data: tvimageData)
self.imageCache.setObject(image!, forKey: imageURL)
dispatch_async(dispatch_get_main_queue(), {() -> Void in
cell.seriesImage.image = nil
cell.seriesImage.image = image
})
}
})
}
}
cell.seriesLabel.text = "\(series.title)"
}
} else {
let series = seriesArray[indexPath.row]
do {
// set image
if let imageURL = NSURL(string: "\(series.seriesimageurl)") {
if let image = imageCache.objectForKey(imageURL) as? UIImage {
cell.seriesImage.image = image
} else {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), {
if let tvimageData = NSData(contentsOfURL: imageURL) {
let image = UIImage(data: tvimageData)
self.imageCache.setObject(image!, forKey: imageURL)
dispatch_async(dispatch_get_main_queue(), {() -> Void in
cell.seriesImage.image = nil
cell.seriesImage.image = image
})
}
})
}
}
cell.seriesLabel.text = "\(series.title)"
}
}
cell.layer.shouldRasterize = true
cell.layer.rasterizationScale = UIScreen.mainScreen().scale
cell.prepareForReuse()
return cell
}
SeriesCollectionViewCell
class SeriesCollectionViewCell: UICollectionViewCell {
@IBOutlet weak var seriesImage: UIImageView!
@IBOutlet weak var seriesLabel: UILabel!
}
Ячейки повторно используются, и вы отправляете изображение из асинхронно, поэтому, когда вы промахиваете ячейку и асинхронно извлекаете новое изображение, тогда старая выборка все еще работает. Вам нужно справиться с этим. Вероятно, самый простой способ - использовать что-то SDWebImage, которое имеет расширение на UIImageView, которое будет обрабатывать это для вас. – Paulw11
@ Paulw11: Да, я полагал, что это связано с тем, что запросы не отменены должным образом или что-то в этом роде. Я надеялся написать код только с помощью UIKit, так как я использую это приложение в качестве учебного опыта, и я чувствую, что полагаюсь на внешнюю инфраструктуру, поражающую эту цель, поскольку это ярлык. Однако я действительно изучал Alamofire/AlamofireImage и SDWebImage, но по какой-то причине после установки контейнеров я не могу импортировать модули (это отдельная проблема, которую я не совсем понял). Я буду использовать это, если мне нужно, хотя, просто хочу сначала обработать его с помощью UIKit. – shadowofjazz
Другой подход - сохранить URL-адрес изображения в качестве свойства вашей ячейки, а затем в закрытии завершения проверить значение свойства по URL-адресу, который вы только что выбрали. Если он не соответствует, не устанавливайте изображение, поскольку ячейка уже была повторно использована. – Paulw11