我应该怎么做才能在 tableView 中加载异步图像?
what should I do to load asynchronous images in tableView?
嗯,我应该在 table 视图中加载图像,我下载并加载成功,但是当我尝试在 table 视图中显示时,它们没有出现,但是,如果我在 table 视图中滚动,图像会出现,但图像不会在单元格中间。
我正在使用 swift 4.2
这几行帮助我下载和加载图像
extension UIImageView {
func downloaded(from url: URL, contentMode mode: UIView.ContentMode = .scaleAspectFit) {
contentMode = mode
URLSession.shared.dataTask(with: url) { data, response, error in
guard
let httpURLResponse = response as? HTTPURLResponse, httpURLResponse.statusCode == 200,
let mimeType = response?.mimeType, mimeType.hasPrefix("image"),
let data = data, error == nil,
let image = UIImage(data: data)
else { return }
DispatchQueue.main.async() {
self.image = self.resizedImageWith(image: image, targetSize: CGSize(width: 100.0, height: 50.0))
}
}.resume()
}
func downloaded(from link: String, contentMode mode: UIView.ContentMode = .scaleAspectFit) {
guard let url = URL(string: link) else { return }
downloaded(from: url, contentMode: mode)
}
}
在我的 table 视图控制器中,我使用此功能下载图像
func loadImages()
{
for img in arrFavServices
{
if let url = img?.logo
{
let imgDownload = UIImageView()
imgDownload.downloaded(from: url, contentMode: .redraw)
arrImages.append(imgDownload)
}
else
{
let imgDownload = UIImageView()
imgDownload.image = UIImage(named: "logo")
arrImages.append(imgDownload)
}
tableView.reloadData()
tableView.layoutIfNeeded()
tableView.layoutSubviews()
utilActivityIndicator.shared.hideLoader(view: view)
}
}
数组 arrFavServices 包含所有图像 url,并且 arrImages 包含之前下载的所有图像。在 viewdidload 中调用了函数 loadImages。
我用这个函数来显示图像
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
if (arrFavServices[indexPath.section]?.logo) != nil
{
if arrImages[indexPath.section].image != nil
{
cell.imageView?.image = arrImages[indexPath.section].image
cell.imageView?.contentMode = .center
}
}
// Configure the cell...
if let color = arrFavServices[indexPath.section]?.color
{
cell.backgroundColor = UIColor(hexString: color)
}
return cell
}
我的错误是什么?请帮助我
我想你有两个选择
您在单元格可见时异步下载图像(我推荐)
下载所有图像并显示单元格可见
如果您下载所有图片会增加应用程序的内存使用量,如果使用过多,iOS 会使您的应用程序崩溃。
第一个路径:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
if let logo = arrFavServices[indexPath.section]?.logo {
// We need download image here
cell.imageView?.downloaded(from: logo, contentMode: .center)
}
// Configure the cell...
if let color = arrFavServices[indexPath.section]?.color {
cell.backgroundColor = UIColor(hexString: color)
}
return cell
}
第二条路径:
您可以使用调度组。 UITableView 正在等待下载所有图像。
// Cache array
var downloadedImages: [UIImage] = []
// Create an instance
var dispatchGroup = DispatchGroup()
func loadImages() {
// Every tick of loop, we enter the group
for img in arrFavServices {
// Join the group
dispatchGroup.enter()
if let url = img?.logo {
let imgDownload = UIImageView()
imgDownload.downloaded(from: url, contentMode: .redraw, completion: { [weak self] downloadedImage in
guard let self = self else { return }
self.downloadedImages.append(downloadedImage)
// And leave group when task is done
dispatchGroup.leave()
})
} else {
let imgDownload = UIImageView()
imgDownload.image = UIImage(named: "logo")
arrImages.append(imgDownload)
// We can leave here too because we add image to array
dispatchGroup.leave()
}
}
// We have to listen group, and that we update tableView or UI todo
dispatchGroup.notify(queue: .main) {
self.tableView.reloadData()
self.tableView.layoutIfNeeded()
self.tableView.layoutSubviews()
self.utilActivityIndicator.shared.hideLoader(view: self.view)
}
}
您可以像下面这样设置完成处理程序
extension UIImageView {
func downloaded(from url: URL, contentMode mode: UIView.ContentMode = .scaleAspectFit, completion: ((UIImage) -> Void)?) {
contentMode = mode
URLSession.shared.dataTask(with: url) { data, response, error in
guard
let httpURLResponse = response as? HTTPURLResponse, httpURLResponse.statusCode == 200,
let mimeType = response?.mimeType, mimeType.hasPrefix("image"),
let data = data, error == nil,
let image = UIImage(data: data)
else { return }
DispatchQueue.main.async() {
completion?(image)
}
}.resume()
}
func downloaded(from link: String, contentMode mode: UIView.ContentMode = .scaleAspectFit, completion: ((UIImage) -> Void)?) {
guard let url = URL(string: link) else { return }
downloaded(from: url, contentMode: mode, completion: completion)
}
}
大哥,你怎么不用第三方库啊?
Sd_webimage, Kingfisher 你可以只 pod 这个库中的一个并且在一行代码中你的图像在你想要的 tableview 索引处可见。
我会推荐使用第三方库在 tableview 中加载图像。
将此添加到 podfile 中。
pod 'SDWebImage'
在 cellForRowAtIndex 中添加这个简单的代码
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if(indexPath.row > arrId.count-1){
// This will return an empty cell if all data is not downloaded and it will avoid the fatal error: index out of range
return UITableViewCell()
}
else{
let cell = tableView.dequeueReusableCell(withIdentifier: "AlbumCustomCell", for: indexPath) as! AlbumCustomCell
cell.lblId.text = String ( self.arrId[indexPath.row] )
cell.lblTitle.text = self.arrAlbumTitleString[indexPath.row]
cell.layer.shouldRasterize = true
cell.layer.rasterizationScale = UIScreen.main.scale
if let url = URL(string: self.arrAlbumThumbnailURLString[indexPath.row]) {
cell.albumThumbnaiilImage.sd_setImage(with: url, placeholderImage: UIImage(named: "placeholder"), options: .continueInBackground, context: nil)
}
return cell
}
}
平滑滚动表格视图需要此代码。
cell.layer.shouldRasterize = true
cell.layer.rasterizationScale = UIScreen.main.scale
I am downloading 5000 images and showing them in the table view.
嗯,我应该在 table 视图中加载图像,我下载并加载成功,但是当我尝试在 table 视图中显示时,它们没有出现,但是,如果我在 table 视图中滚动,图像会出现,但图像不会在单元格中间。
我正在使用 swift 4.2
这几行帮助我下载和加载图像
extension UIImageView {
func downloaded(from url: URL, contentMode mode: UIView.ContentMode = .scaleAspectFit) {
contentMode = mode
URLSession.shared.dataTask(with: url) { data, response, error in
guard
let httpURLResponse = response as? HTTPURLResponse, httpURLResponse.statusCode == 200,
let mimeType = response?.mimeType, mimeType.hasPrefix("image"),
let data = data, error == nil,
let image = UIImage(data: data)
else { return }
DispatchQueue.main.async() {
self.image = self.resizedImageWith(image: image, targetSize: CGSize(width: 100.0, height: 50.0))
}
}.resume()
}
func downloaded(from link: String, contentMode mode: UIView.ContentMode = .scaleAspectFit) {
guard let url = URL(string: link) else { return }
downloaded(from: url, contentMode: mode)
}
}
在我的 table 视图控制器中,我使用此功能下载图像
func loadImages()
{
for img in arrFavServices
{
if let url = img?.logo
{
let imgDownload = UIImageView()
imgDownload.downloaded(from: url, contentMode: .redraw)
arrImages.append(imgDownload)
}
else
{
let imgDownload = UIImageView()
imgDownload.image = UIImage(named: "logo")
arrImages.append(imgDownload)
}
tableView.reloadData()
tableView.layoutIfNeeded()
tableView.layoutSubviews()
utilActivityIndicator.shared.hideLoader(view: view)
}
}
数组 arrFavServices 包含所有图像 url,并且 arrImages 包含之前下载的所有图像。在 viewdidload 中调用了函数 loadImages。 我用这个函数来显示图像
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
if (arrFavServices[indexPath.section]?.logo) != nil
{
if arrImages[indexPath.section].image != nil
{
cell.imageView?.image = arrImages[indexPath.section].image
cell.imageView?.contentMode = .center
}
}
// Configure the cell...
if let color = arrFavServices[indexPath.section]?.color
{
cell.backgroundColor = UIColor(hexString: color)
}
return cell
}
我的错误是什么?请帮助我
我想你有两个选择
您在单元格可见时异步下载图像(我推荐)
下载所有图像并显示单元格可见
如果您下载所有图片会增加应用程序的内存使用量,如果使用过多,iOS 会使您的应用程序崩溃。
第一个路径:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
if let logo = arrFavServices[indexPath.section]?.logo {
// We need download image here
cell.imageView?.downloaded(from: logo, contentMode: .center)
}
// Configure the cell...
if let color = arrFavServices[indexPath.section]?.color {
cell.backgroundColor = UIColor(hexString: color)
}
return cell
}
第二条路径:
您可以使用调度组。 UITableView 正在等待下载所有图像。
// Cache array
var downloadedImages: [UIImage] = []
// Create an instance
var dispatchGroup = DispatchGroup()
func loadImages() {
// Every tick of loop, we enter the group
for img in arrFavServices {
// Join the group
dispatchGroup.enter()
if let url = img?.logo {
let imgDownload = UIImageView()
imgDownload.downloaded(from: url, contentMode: .redraw, completion: { [weak self] downloadedImage in
guard let self = self else { return }
self.downloadedImages.append(downloadedImage)
// And leave group when task is done
dispatchGroup.leave()
})
} else {
let imgDownload = UIImageView()
imgDownload.image = UIImage(named: "logo")
arrImages.append(imgDownload)
// We can leave here too because we add image to array
dispatchGroup.leave()
}
}
// We have to listen group, and that we update tableView or UI todo
dispatchGroup.notify(queue: .main) {
self.tableView.reloadData()
self.tableView.layoutIfNeeded()
self.tableView.layoutSubviews()
self.utilActivityIndicator.shared.hideLoader(view: self.view)
}
}
您可以像下面这样设置完成处理程序
extension UIImageView {
func downloaded(from url: URL, contentMode mode: UIView.ContentMode = .scaleAspectFit, completion: ((UIImage) -> Void)?) {
contentMode = mode
URLSession.shared.dataTask(with: url) { data, response, error in
guard
let httpURLResponse = response as? HTTPURLResponse, httpURLResponse.statusCode == 200,
let mimeType = response?.mimeType, mimeType.hasPrefix("image"),
let data = data, error == nil,
let image = UIImage(data: data)
else { return }
DispatchQueue.main.async() {
completion?(image)
}
}.resume()
}
func downloaded(from link: String, contentMode mode: UIView.ContentMode = .scaleAspectFit, completion: ((UIImage) -> Void)?) {
guard let url = URL(string: link) else { return }
downloaded(from: url, contentMode: mode, completion: completion)
}
}
大哥,你怎么不用第三方库啊? Sd_webimage, Kingfisher 你可以只 pod 这个库中的一个并且在一行代码中你的图像在你想要的 tableview 索引处可见。
我会推荐使用第三方库在 tableview 中加载图像。
将此添加到 podfile 中。
pod 'SDWebImage'
在 cellForRowAtIndex 中添加这个简单的代码
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if(indexPath.row > arrId.count-1){
// This will return an empty cell if all data is not downloaded and it will avoid the fatal error: index out of range
return UITableViewCell()
}
else{
let cell = tableView.dequeueReusableCell(withIdentifier: "AlbumCustomCell", for: indexPath) as! AlbumCustomCell
cell.lblId.text = String ( self.arrId[indexPath.row] )
cell.lblTitle.text = self.arrAlbumTitleString[indexPath.row]
cell.layer.shouldRasterize = true
cell.layer.rasterizationScale = UIScreen.main.scale
if let url = URL(string: self.arrAlbumThumbnailURLString[indexPath.row]) {
cell.albumThumbnaiilImage.sd_setImage(with: url, placeholderImage: UIImage(named: "placeholder"), options: .continueInBackground, context: nil)
}
return cell
}
}
平滑滚动表格视图需要此代码。
cell.layer.shouldRasterize = true
cell.layer.rasterizationScale = UIScreen.main.scale
I am downloading 5000 images and showing them in the table view.