为什么我的 UITableView 滚动高分辨率图像时不那么流畅
Why is my UITableView scrolling not so smooth for High resolution images
我有一个问题,我在 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
}
您在主线程上使用 NSData(contentsOf:)
的第一次尝试肯定不会很好。即阻塞主线程执行同步网络请求。 Alamofire 方法更有前途,将请求推送到异步进程中,这应该可以在很大程度上缓解问题。
话虽如此,使用大于您将在其中使用它们的控件的资源可能会导致 UI 出现一些卡顿,因为大型资源在控件内未压缩并动态重新缩放。无论您要获取的图像大小如何,您都需要调整它们的大小以适合您的 UI。使用 AlamofireImage 的 setImage(withURL:)
.
很容易做到这一点
例如,在 AlamofireImage 4 中:
let urls = (1000...2000).compactMap { URL(string: "https://i.picsum.photos/id/\([=10=])/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[[=12=].row] }.forEach { url in
let request = URLRequest(url: url)
let key = url.absoluteString
UIImageView.af.sharedImageDownloader.download(request, cacheKey: key, filter: filter, completion: nil)
}
}
}
我有一个问题,我在 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
}
您在主线程上使用 NSData(contentsOf:)
的第一次尝试肯定不会很好。即阻塞主线程执行同步网络请求。 Alamofire 方法更有前途,将请求推送到异步进程中,这应该可以在很大程度上缓解问题。
话虽如此,使用大于您将在其中使用它们的控件的资源可能会导致 UI 出现一些卡顿,因为大型资源在控件内未压缩并动态重新缩放。无论您要获取的图像大小如何,您都需要调整它们的大小以适合您的 UI。使用 AlamofireImage 的 setImage(withURL:)
.
例如,在 AlamofireImage 4 中:
let urls = (1000...2000).compactMap { URL(string: "https://i.picsum.photos/id/\([=10=])/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[[=12=].row] }.forEach { url in
let request = URLRequest(url: url)
let key = url.absoluteString
UIImageView.af.sharedImageDownloader.download(request, cacheKey: key, filter: filter, completion: nil)
}
}
}