下载 JSON 时如何解决 UITableView 滚动性能滞后的问题?
Posted
技术标签:
【中文标题】下载 JSON 时如何解决 UITableView 滚动性能滞后的问题?【英文标题】:How do I fix laggy UITableView scrolling performance when downloading JSON? 【发布时间】:2017-05-14 18:26:40 【问题描述】:在我的应用程序中,我从 Internet 下载了一个 JSON 文件,并用该文件中的项目填充了一个 UITableView。它运行良好,没有问题或错误,但滚动性能非常滞后,并且 UI 出现了一点点小故障。
我认为这是因为我从 JSON 文件下载的图像,所以我研究了多线程,但我认为我做得不对,因为它确实 em> 加载速度快了很多,但滚动性能还是和以前一样。
谁能告诉我如何解决这个问题?这个 UITableView 是应用程序中最重要的东西,我花了很多时间试图修复它。谢谢!
这是我的代码-
import UIKit
class ViewController: UIViewController, UITableViewDataSource
@IBOutlet weak var tableView: UITableView!
var nameArray = [String]()
var idArray = [String]()
var ageArray = [String]()
var genderArray = [String]()
var descriptionArray = [String]()
var imgURLArray = [String]()
let myActivityIndicator = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.gray)
final let urlString = "https://pbsocfilestorage.000webhostapp.com/jsonDogs.json"
override func viewDidLoad()
super.viewDidLoad()
self.downloadJsonWithURL()
// Activity Indicator
myActivityIndicator.center = view.center
myActivityIndicator.hidesWhenStopped = true
myActivityIndicator.startAnimating()
view.addSubview(myActivityIndicator)
override func didReceiveMemoryWarning()
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
func downloadJsonWithURL()
let url = NSURL(string:urlString)
URLSession.shared.dataTask(with: (url as? URL)!, completionHandler: (data, response, error) ->
Void in
print("Good so far...")
if let jsonObj = try? JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? NSDictionary
print(jsonObj!.value(forKey: "dogs"))
if let dogArray = jsonObj!.value(forKey: "dogs") as? NSArray
print("Why u no work!")
for dog in dogArray
if let dogDict = dog as? NSDictionary
if let name = dogDict.value(forKey: "name")
self.nameArray.append(name as! String)
if let name = dogDict.value(forKey: "id")
self.idArray.append(name as! String)
if let name = dogDict.value(forKey: "age")
self.ageArray.append(name as! String)
if let name = dogDict.value(forKey: "gender")
self.genderArray.append(name as! String)
if let name = dogDict.value(forKey: "image")
self.imgURLArray.append(name as! String)
if let name = dogDict.value(forKey: "description")
self.descriptionArray.append(name as! String)
OperationQueue.main.addOperation (
self.myActivityIndicator.stopAnimating()
self.tableView.reloadData()
)
).resume()
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
return nameArray.count
func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
return UITableViewAutomaticDimension;
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
let imgURL = NSURL(string: imgURLArray[indexPath.row])
let cell = tableView.dequeueReusableCell(withIdentifier: "reusableCell") as! TableViewCell
URLSession.shared.dataTask(with: (imgURL as! URL), completionHandler: (data, resp, error) -> Void in
if (error == nil && data != nil)
OperationQueue.main.addOperation(
cell.dogNameLabel.text = self.nameArray[indexPath.row]
cell.idLabel.text = self.idArray[indexPath.row]
cell.ageLabel.text = self.ageArray[indexPath.row]
cell.genderLabel.text = self.genderArray[indexPath.row]
print("Cell info was filled in!")
if imgURL != nil
let data = NSData(contentsOf: (imgURL as? URL)!)
cell.dogImage.image = UIImage(data: data as! Data)
)
).resume()
return cell
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
if segue.identifier == "showDog"
if let indexPath = self.tableView.indexPathForSelectedRow
let detailViewController = segue.destination as! DetailViewController
detailViewController.imageString = imgURLArray[indexPath.row]
detailViewController.nameString = nameArray[indexPath.row]
detailViewController.idString = idArray[indexPath.row]
detailViewController.ageString = ageArray[indexPath.row]
detailViewController.descriptionString = descriptionArray[indexPath.row]
detailViewController.genderString = genderArray[indexPath.row]
【问题讨论】:
除了接受来自@vadian 的响应之外,您可能还想在viewDidLoad
中指定一个tableView.estimatedRowHeight
并将tableView.rowHeight
设置为UITableViewAutomaticDimension
【参考方案1】:
有一个很大的错误。您正在使用 dataTask
加载数据,但您根本没有使用返回的数据。而不是您使用同步contentsOf
第二次加载数据。不要那样做。
并且不要更新异步完成块中的标签。字符串与图像数据无关。
这样更有效率:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
let imgURL = URL(string: imgURLArray[indexPath.row])
let cell = tableView.dequeueReusableCell(withIdentifier: "reusableCell", for: indexPath) as! TableViewCell
cell.dogNameLabel.text = self.nameArray[indexPath.row]
cell.idLabel.text = self.idArray[indexPath.row]
cell.ageLabel.text = self.ageArray[indexPath.row]
cell.genderLabel.text = self.genderArray[indexPath.row]
print("Cell info was filled in!")
URLSession.shared.dataTask(with: imgURL!) (data, resp, error) in
if let data = data
OperationQueue.main.addOperation(
cell.dogImage.image = UIImage(data: data)
)
.resume()
return cell
注意:强烈建议您不要使用多个数组作为数据源。它非常容易出错。使用自定义结构或类。并使用URL
实例而不是字符串创建imgURLArray
。这也更有效率。
不过,您应该使用下载管理器来缓存图像并在单元格离开屏幕时取消下载。目前,当用户滚动并为此特定单元格再次调用 cellForRow
时,将再次下载每个图像。
【讨论】:
谢谢!滚动终于流畅了!我正在按照教程将 JSON 下载到 TableView 中,我想它不是很好。我会考虑你的笔记。以上是关于下载 JSON 时如何解决 UITableView 滚动性能滞后的问题?的主要内容,如果未能解决你的问题,请参考以下文章
下载大尺寸json时如何解决Uncaught RangeError
在iOS中单击按钮时如何在UITableView中获取特定的JSON数据(目标c)?