Почему моя прокрутка UITableView не так гладко для изображений с высоким разрешением - PullRequest
0 голосов
/ 29 февраля 2020

У меня проблема с набором изображений высокого разрешения, которые я отображаю в UITableView.

Я что-то не так делаю, когда дело доходит до кэширования изображений. Я также попробовал и потерпел неудачу в аналогичной реализации с библиотекой AlamofireImage, и кажется, что прокрутка в обеих реализациях не слишком плавная.

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

Может кто-нибудь сказать мне, в чем может быть проблема?

код выглядит следующим образом:

override func viewDidLoad() {
    super.viewDidLoad()

    for i in 1000...2000{
        let url = "https://i.picsum.photos/id/\(i)/3000/2000.jpg";
        imageUrlArray.append(url)
        print(url)
    }
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let cell = tableView.dequeueReusableCell(withIdentifier: "ImageCellId") as! ImageTableViewCell


        let imageUrl = imageUrlArray[indexPath.row]

        cell.imgView.image = nil
        cell.tag = indexPath.row

        if let image = imageCache.object(forKey: indexPath.row as AnyObject){
            DispatchQueue.main.async {
                cell.imgView?.image = image as? UIImage
            }
        }

        DispatchQueue.main.async {
            let data = NSData(contentsOf: URL(string: imageUrl)!)
            guard let imageData = data else{
                return
            }
            DispatchQueue.main.async {
                cell.imgView.image = UIImage(data:imageData as Data)
                imageCache.setObject(imageData, forKey: indexPath.row as AnyObject)
                print("Setting object")
            }
        }

        return cell
    }

С Alamofire :

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "ImageCellId") as! ImageTableViewCell
    let imageUrl = imageUrlArray[indexPath.row]

    cell.imgView.image = nil
    cell.tag = indexPath.row

    Alamofire.request(imageUrl).responseData { response in

        if case .success(let image) = response.result {
            DispatchQueue.main.async {
                if(cell.tag == indexPath.row){
                    guard let imageData = UIImage(data: image)else{
                        return
                    }

                    cell.imgView.image = imageData
                }
            }
        }
    }
   return cell
  }

1 Ответ

0 голосов
/ 01 марта 2020

Ваша первая попытка с NSData(contentsOf:) в главном потоке определенно не будет работать. Это блокирует основной поток для выполнения синхронных сетевых запросов. Подход Alamofire является более перспективным, подталкивая запросы в асинхронный процесс, который должен в значительной степени облегчить проблему.

Как уже было сказано, использование активов, которые больше, чем элемент управления, в котором вы будете их использовать, может привести к некоторому заиканию в пользовательском интерфейсе, так как большие активы распаковываются и динамически изменяются в пределах элемента управления. Независимо от размера изображений, которые вы выбираете, вы захотите изменить их размер в соответствии с вашим пользовательским интерфейсом. Это легко сделать с помощью setImage(withURL:).

AlamofireImage. Например, в AlamofireImage 4:

let urls = (1000...2000).compactMap { URL(string: "https://i.picsum.photos/id/\($0)/3000/2000.jpg") }
let placeholder = UIImage()
let filter: AspectScaledToFillSizeFilter = {
    let scale = UIScreen.main.scale
    let size = CGSize(width: 50 * scale, height: 50 * scale)
    return AspectScaledToFillSizeFilter(size: size)
}()

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath) as! CustomCell

    let url = urls[indexPath.row]
    cell.customImageView.af.setImage(withURL: url, cacheKey: url.absoluteString, placeholderImage: placeholder, filter: filter, imageTransition: .crossDissolve(0.2), runImageTransitionIfCached: false)

    return cell
}

Это загружает изображение с высоким разрешением, изменяет его размер соответственно для просмотра изображения (в данном случае мое изображение имеет размер 50 × 50 точек) и выполняет кэширование в памяти.


Если вы хотите выполнить предварительную выборку изображений, вы можете указать источник данных предварительной выборки:

override func viewDidLoad() {
    super.viewDidLoad()

    tableView.prefetchDataSource = self
}

И загрузите изображения:

extension ViewController: UITableViewDataSourcePrefetching {
    func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) {
        indexPaths.map { urls[$0.row] }.forEach { url in
            let request = URLRequest(url: url)
            let key = url.absoluteString
            UIImageView.af.sharedImageDownloader.download(request, cacheKey: key, filter: filter, completion: nil)
        }
    }
}
...