#ios #swift #function #uicollectionviewcell #nsurlsession
Вопрос:
У меня есть ячейка, и я использую URLSessionTask внутри нее для некоторых изображений. Когда ячейка скроется с экрана, prepareForReuse
я отменяю задачу, и все работает нормально. Поскольку я делаю несколько вещей с изображением, как только я получу его из задачи, я хочу создать функцию для всего. Проблема в том, что я не могу передать task: URLSessionDataTask?
в качестве параметра, потому что это a let constant
. Я понимаю, что ошибка не может быть присвоена значению: «задача» является константой «let», но я не могу понять, как ее обойти, потому что мне нужно отменить задачу после запуска prepareForReuse?
func setImageUsingURLSessionTask(photoUrlStr: String, imageView: UIImageView, task: URLSessionDataTask?)
if let cachedImage = imageCache.object(forKey: photoUrlStr as AnyObject) as? UIImage {
let resizedImage = funcToResizeImage(cachedImage)
imageView.image = resizedImage
return
}
guard let url = URL(string: photoUrlStr) else { return }
task = URLSession.shared.dataTask(with: url, completionHandler: { (data, response, error) in
// eventually resize image, set it to the imageView, and save it to cache
})
task?.resume()
}
Вот ячейка, если не ясно. Как только cellForItem запускается и MyObject инициализируется, я передаю функции photoUrlStr, ImageView и задачу. Если ячейка прокручивается за пределами экрана, prepareForReuse
задача отменяется, поэтому неправильное изображение никогда не появляется. Это работает на 100% нормально, если я установлю URLSessionTask внутри самой ячейки, а не внутри функции.
class MyCell: UICollectionViewCell {
lazy var photoImageView: UIImageView = {
// ...
}()
var task: URLSessionTask?
var myObject: MyObject? {
didSet {
guard let photoUrlStr = myObject?.photoUrlStr else { return }
setImageUsingURLSessionTask(photoUrlStr: photoUrlStr, imageView: photoImageView, task: task)
}
}
override func prepareForReuse() {
super.prepareForReuse()
task?.cancel()
task = nil
photoImageView.image = nil
}
}
Комментарии:
1. Функция
setImageUsingURLSessionTask()
может просто возвращать задачу URLSession. Передача ему задачи в качестве параметра для меня не имеет смысла — он все равно не будет использоваться. Вам действительно следует улучшить дизайн и явно разделить три части функции: попробуйте загрузить из кэша, запустите URLSessionTask, обработайте результат.2. Ты потерял меня. Я передаю ему задачу просто загрузить изображение, если изображения нет в кэше. Функция ничего не возвращает, где вы видите оператор return в функции?. Когда я беру код за пределами функции, он отлично работает без проблем. Если изображения нет в кэше, я запускаю задачу. Единственное, что я сейчас делаю, — это помещаю код в функцию. Я только что попробовал функцию с ответом на мой вопрос, и она отлично работает.
3. Ваша функция создает новое значение задачи, если изображения нет в кэше. Он никогда не использует параметр
task
, который является необязательным даже.inout
здесь это не совсем уместно. Вместо этого вы можете вернуть необязательную задачу URLSession в своей функции: это произойдетnil
, если вы не создали задачу, в противном случае она вернет только что созданную задачу.4. Как он может не использовать этот параметр
task
? Внутри функцииtask = URL...
, какую задачу она использует , если она не использует параметр? Внутри функции нет ничего, что говорило быvar task: URLSessionTask?
5. да 🙂 на самом деле. С этим небольшим изменением код станет намного чище.
Ответ №1:
Вы можете передать свою задачу в качестве inout
параметра. Упрощенной версией вашей функции была бы:
func changeDataTask(inout task: URLSessionDataTask) {
task = // You can change it
}
Переменная, которую вы передаете функции, должна быть var
. Вы бы назвали это так:
var task = // Declare your initial datatask
changeDataTask(task: amp;task)