Как передать URLSessionTask в качестве параметра

#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)