Сообщение от отладчика: Прервано из-за проблемы с памятью При прокрутке в UITableView/UICollectionView с изображениями gif Kingfisher Library

Фрагмент кода:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell: BroadCastFeedTableViewCell = broadCastTableView.dequeueReusableCell(withIdentifier: "broadCastFeedCell") as BroadCastFeedTableViewCell

    cell.singlePicImageView.kf.setImage(with: URL(string: (self.broadCastArray[indexPath.row].images_url?[0])!), placeholder: nil, options: nil, progressBlock: nil) 
            { (theImage, error, cache, url) in
                if theImage != nil{
                    let imageHeight = self.getAspectRatioOfDownloadedImages(resolution: self.broadCastArray[indexPath.row].image_resolution![0])
                    cell.collectionContentViewHeightConstraint.constant = imageHeight

                    cell.layoutSubviews()
                    cell.layoutIfNeeded()

                }else {
                    let placeHolderCenterCordi = UIView().getViewRelationWithSuperSuperView(viewControllerView: cell.collectionContentView, 
                                                                    subView: cell.singlePicImageView, subObjFrame: cell.singlePicImageView.frame)

                    cell.singlePicImageView.addPlaceHolderImageView(cordinates: placeHolderCenterCordi.center)
                }
               self.broadCastTableView.rowHeight = UITableViewAutomaticDimension
            }
}

В приведенном выше коде я использовал библиотеку Kingfisher для загрузки изображения с удаленного сервера, всякий раз, когда следующий код загружает определенные изображения (GIF, JPEG, PNG), которые могут иметь большой размер (приблизительно 2-5 МБ), приложение завершает работу из-за проблемы с памятью. В iPhone 5s он завершается мгновенно, как только запускается приложение, а в других моделях iPhone (7, 6s) он завершается после прокрутки в течение определенного времени. Я также проверил распределение и утечку, но я мало что понял/нашел об этой проблеме.

Я также прикрепил график профилирования. Это показывает, что таких утечек памяти нет, но из-за какой-то проблемы приложение завершает работу:

Следующее изображение показывает, что таких утечек памяти нет, но из-за какой-то проблемы приложение завершает работу


person Manish Patel    schedule 01.03.2019    source источник


Ответы (3)


У меня было много проблем с загрузкой изображений в память. Я не могу быть уверен в вашем случае, но я могу дать вам несколько полезных советов.

  1. Посмотрите на UITableViewDataSourcePrefetching. Это способ загрузки изображений до того, как они будут отображены в ячейке.
  2. Попробуйте создать где-нибудь вспомогательную функцию, которая запускает загрузку и позволяет отменить эту загрузку. Например, когда вы быстро прокручиваете таблицу вниз, каждая ячейка начнет загрузку изображения, даже если оно не было показано. Вы можете отменить загрузку, если ячейка исчезла.
  3. Ячейки должны быть в основном элементом пользовательского интерфейса в вашем коде. Идея состоит в том, чтобы попытаться вывести сетевые запросы из самой ячейки и убедиться, что ваша ячейка содержит только элементы (изображения, метки, представления) для рендеринга, ячейка имеет функцию func configure (withModel: Model) и что на cellForRow вы просто передаете ему данные для рендеринга. Ячейки повторно используются и часто обновляются, вы не должны выполнять с ними кучу вещей. Помните, что когда ячейка загружается, она будет вызывать эти функции, затем она может исчезнуть с экрана и вернуться обратно, и все это будет выполняться снова и снова.
  4. Попросите класс ячеек выполнить правильные обновления и обновления макета и постарайтесь не делать этого в файле cellForRow. Все, что вы можете сделать, это просто убедиться, что изображение получает изображение, но не полагаться на выполнение изменений ячеек, и эта загрузка изображения является асинхронной, и этой ячейки может даже не быть там, когда загрузка заканчивается.
  5. Кэширование. Можете ли вы кэшировать эти изображения или они постоянно меняются? убедитесь, что вы понимаете, как KF кэширует ваши изображения, и что кэширование вам нужно. Если нет, приспособьтесь.
  6. [придирки] вы звоните cell.layoutSubviews(), а затем cell.layoutIfNeeded(). Первый — принудительно вызвать layoutSubviews, второй — проверить, есть ли что-то, что нужно выложить перед вызовом layoutSubView. Если вы хотите пометить представление для размещения, вы можете использовать setNeedsLayout(). это сделает макет представления обновленным в следующем цикле.
person gmogames    schedule 01.03.2019
comment
Ницца. будет полезно - person Rakesh Mandloi; 01.03.2019

Я думаю, что в вашем коде вы используете «Я» в качестве сильных рефренов, поэтому он создает сильный цикл ссылок из-за этого создает утечку памяти. так что на этом этапе вы можете попробовать [weak self], а затем запустить свой код

cell.singlePicImageView.kf.setImage(with: URL(string: (self.broadCastArray[indexPath.row].images_url?[0])!), placeholder: nil, options: nil, progressBlock: nil) 
        { [weak self] (theImage, error, cache, url) in
            if theImage != nil{
                let imageHeight = self?.getAspectRatioOfDownloadedImages(resolution: self?.broadCastArray[indexPath.row].image_resolution![0])
                cell.collectionContentViewHeightConstraint.constant = imageHeight

                cell.layoutSubviews()
                cell.layoutIfNeeded()

            }else {
                let placeHolderCenterCordi = UIView().getViewRelationWithSuperSuperView(viewControllerView: cell.collectionContentView, 
                                                                subView: cell.singlePicImageView, subObjFrame: cell.singlePicImageView.frame)

                cell.singlePicImageView.addPlaceHolderImageView(cordinates: placeHolderCenterCordi.center)
            }
           self?.broadCastTableView.rowHeight = UITableViewAutomaticDimension
        }
person Rakesh Mandloi    schedule 01.03.2019
comment
Нет, брат, утечек памяти нет, проверьте прикрепленное изображение профилирования. - person Manish Patel; 01.03.2019

Отвечая на мой собственный вопрос

Следующее сработало для меня

Я использовал класс AnimatedImageView для своего UIImageView, предоставленного библиотекой зимородка.

let imageView = AnimatedImageView()
imageView.kf.setImage(with: URL(string: "your_image"), placeholder: nil, options: [.targetCache(ImageCache(name: "your_cache_name")), .backgroundDecode], progressBlock: nil) { (image, error, cache, url) in 
  // some code
}

Примечание Важно

[.targetCache(ImageCache(имя: "your_cache_name")), .backgroundDecode]

В приведенном выше коде для атрибута options я использовал свой собственный кеш (ImageCache(name: "your_cache_name")) и попросил зимородка декодировать изображение в фоновом режиме.

person Manish Patel    schedule 04.03.2019