У меня есть UITableView
, и мне нужно, чтобы каждая из его ячеек загружала изображение с предоставленного URL-адреса и отображала его. Это выглядит довольно распространенным сценарием, и я действительно нашел несколько сообщений и вопросов, связанных с этим, но мне все еще не ясно, какой подход должен быть лучшим.
Первый, у меня есть один, использующий Data(contentsOf:)
. Это код, который у меня есть в моем UITableViewCell
:
class MyCell: UITableViewCell {
@IBOutlet weak var activityIndicator: UIActivityIndicatorView!
@IBOutlet weak var imageView: UIImageView!
var model: Model? {
willSet {
activityIndicator.startAnimating()
configureImage(showImage: false, showActivity: true)
}
didSet {
guard let imageSmallUrlStr = model?.imageSmallUrl, let imageUrl = URL(string: imageSmallUrlStr) else {
activityIndicator.stopAnimating()
configureImage(showImage: false, showActivity: false)
return
}
DispatchQueue.global(qos: .userInitiated).async {
var image: UIImage?
let imageData = try? Data(contentsOf: imageUrl)
if let imageData = imageData {
image = UIImage(data: imageData)
}
DispatchQueue.main.async {
self.imageView.image = image
self.configureImage(showImage: true, showActivity: false)
}
}
}
override func awakeFromNib() {
super.awakeFromNib()
configureImage(showImage: false, showActivity: false)
}
override func prepareForReuse() {
super.prepareForReuse()
model = nil
}
// Other methods
}
Этот подход выглядит довольно простым и быстрым, по крайней мере, когда я тестирую его на симуляторе. Тем не менее, у меня есть некоторые вопросы по этому поводу:
- Действительно ли уместно загружать изображение с URL-адреса
HTTP
с помощьюData(contentsOf:)
? Это работает, но, возможно, это больше подходит для получения файлов, которые у вас есть, или других вещей, и это не лучшее решение для работы в сети. - Я предполагаю, что выполнение этого действия в глобальной асинхронной очереди — правильное решение, верно?
- Возможно ли при таком подходе отменить загрузку этого изображения, если URL-адрес изображения обновлен, и мне нужно загрузить другое? Кроме того, следует ли отменить загрузку, когда ячейка удаляется из очереди из таблицы, или это делается автоматически?
- Кроме того, я не уверен в этом: поскольку несколько ячеек будут отображаться в таблице одновременно, эти ячейки должны загружаться и показывать свое изображение одновременно. Также может случиться так, что после завершения загрузки изображения соответствующая ячейка будет удалена из очереди из таблицы, поскольку пользователь прокрутил ее. Гарантирует ли этот подход, что несколько ячеек одновременно загружают изображение и что каждое загруженное изображение правильно устанавливается в соответствующую ячейку?
Теперь у меня есть другой подход, использующий URLSession
:
class MyCell: UITableViewCell {
@IBOutlet weak var activityIndicator: UIActivityIndicatorView!
@IBOutlet weak var imageView: UIImageView!
var imageTask: URLSessionDownloadTask?
var model: Model? {
willSet {
activityIndicator.startAnimating()
configureImage(showImage: false, showActivity: true)
}
didSet {
imageTask?.cancel()
guard let imageSmallUrlStr = model?.imageSmallUrl, let imageUrl = URL(string: imageSmallUrlStr) else {
activityIndicator.stopAnimating()
configureImage(showImage: false, showActivity: false)
return
}
imageTask = NetworkManager.sharedInstance.getImageInBackground(imageUrl: imageUrl, completion: { [weak self] (image, error) in
DispatchQueue.main.async {
guard error == nil else {
self?.activityIndicator.stopAnimating()
self?.configureImage(showImage: false, showActivity: false)
return
}
self?.imageView.image = image
self?.activityIndicator.stopAnimating()
self?.configureImage(showImage: true, showActivity: false)
}
})
}
}
// Other methods
}
При таком подходе я могу вручную отменить задачу, но когда я запускаю приложение на симуляторе, оно выглядит медленнее. На самом деле, я получаю несколько ошибок «отменено» при попытке загрузить многие изображения. Но таким образом я мог бы обрабатывать фоновые загрузки.
Вопросы об этом подходе:
- Как я могу убедиться, что загруженное изображение отображается в соответствующей ячейке? Та же проблема, что описана ранее: в этот момент ячейка могла быть удалена из очереди из таблицы.
Этот вопрос связан с обоими подходами:
- Я не хочу сохранять изображения в файлы, но я не хочу загружать снова, если ячейка снова отображается, а я уже это сделал. Каким должен быть лучший способ их кэширования?
Swift 3
и предпочитаю не использовать здесь никаких сторонних разработчиков. - person AppsDev   schedule 01.05.2017