Reputation: 421
When the button is tapped to segue to the tableview, it takes about 5 seconds for it to segue. After it finally segues, when the tableview scrolls, it stutters and sometimes crashes. The tableview is populated from a local json file and references local images. The images are optimized to low sizes. What is causing this and how can I optimize/fix my code to stop this from happening?
import UIKit
class PDList: UIViewController, UITableViewDelegate, UITableViewDataSource {
@IBOutlet weak var pdTableView: UITableView!
var pdArt = [Decode]()
override func viewDidLoad() {
super.viewDidLoad()
json()
pdTableView.delegate = self
pdTableView.dataSource = self
}
func json() {
let path = Bundle.main.path(forResource: "palmdesert", ofType: "json")
let url = URL(fileURLWithPath: path!)
do {
let data = try Data(contentsOf: url)
self.pdArt = try JSONDecoder().decode([Decode].self, from: data)
}
catch {}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return pdArt.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .subtitle, reuseIdentifier: "pdCell")
let image = UIImage(named: pdArt[indexPath.row].pic)
cell.textLabel?.text = pdArt[indexPath.row].art
cell.detailTextLabel?.text = pdArt[indexPath.row].artist.capitalized
cell.imageView?.image = image
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "pdDetail", sender: self)
self.pdTableView.deselectRow(at: indexPath, animated: true)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destination = segue.destination as? PDDetail {
destination.pdArt = pdArt[(pdTableView.indexPathForSelectedRow?.row)!]
}
}
@IBAction func done(sender: AnyObject) {
dismiss(animated: true, completion: nil)
}
}
JSON Example:
{
"art": "Agave",
"desc": "Agave by Michael Watling serves as the City's entry monument and is inspired by the imagery of the agave, a succulent native to the desert. The stone forms are representative of Palm Desert's many well-managed resources for survival and growth.",
"artist": "Michael Watling",
"lat": 33.7215,
"long": -116.362,
"pic": "test.png"
}
Let me know if you need any other information. Any help is appreciated.
Upvotes: 2
Views: 453
Reputation: 17382
I built a sample UITableView
project with an asset library of 20 large jpeg images of 4032 × 3024
to feed in via UIImage(named:)
to my cells.
This was vastly overspec for an image view of 120 x 70
so a max requirement of 360 x 210
.
The time profiler showed this for scrolling in an entirely new batch of 12 cells.
Roughly 54ms per cell (650/12). However even large JPGs take advantage of hardware decoding so not too bad.
A modern iWidget at 60Hz refresh gives you a maximum of 16ms per frame to refresh the cell. So I got stuttering.
Replacing the images with appropriately scaled images (360 x 210 ) gives this.
Roughly 14ms per cell. The table scrolls mostly smooth.
So the problem here is likely one of these things.
3x
the size of the image view. pngcrush
. Make sure your images are PNG or JPEG. e.g GIF would be bad. Upvotes: 1
Reputation: 5086
My idea is to make a class or Struct something like this.
struct ObjectFromJSON {
var art = ""
var desc = ""
var artist = ""
var lat = 0.0
var long = 0.0
var pic = ""
}
where you decode the data create an array:
var decodedData = [ObjectFromJSON]()
then add all the decoded data to this array. If that will not help then try to add a CocoaPod called SwiftyJSON it makes JSON decoding a breeze and might help.
after decoding just set the info into the ObjectFromJSON object and append it to the decodedData array.
let decodedArt = json["art"].stringValue
let decodedDesc = json["desc"].stringValue
let decodedArtist = json["artist"].stringValue
let decodedLat = json["lat"].doubleValue
let decodedLong = json["long"].doubleValue
let decodedPic = json["pic"].stringValue
let newObject = ObjectFromJSON(art: decodedArt, desc: decodedDesc, artist: decodedArtist, lat: decodedLat, long: decodedLong, pic: decodedPic)
decodedData.append(newObject)
this is based on your JSON however if you have more than 1 object in that json than it makes sense to put them into an array and then decoding would look a little different for example if you number the objects than would be something like:
let decodedArt = json[0]["art"].stringValue
if you have multiple JSON files than the first solution should be fine
Upvotes: 0
Reputation: 2496
Dequeue cells instead of creating new one every time. Change cellForRow to the following:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("pdCell", forIndexPath: indexPath)
let image = UIImage(named: pdArt[indexPath.row].pic)
cell.textLabel?.text = pdArt[indexPath.row].art
cell.detailTextLabel?.text = pdArt[indexPath.row].artist.capitalized
cell.imageView?.image = image
return cell
}
Upvotes: 0