1

I have the following layout:enter image description here When scrolling the tableView fps drops to around 25 and it becomes very jittering.

I think it's my implementation of the collectionView since a lot of operations are performed in cellForIndexAtPath. But I can't see what can be optimized?

extension MyTableViewController: UICollectionViewDelegate, UICollectionViewDataSource {

func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
    // No sections are longer than 99
    if(collectionView.tag < 100)
    {
        let code = codes0[collectionView.tag].objectForKey("code") as! String

        return code.componentsSeparatedByString(",").count
    }
    else if(collectionView.tag < 200)
    {
        let code = codes1[collectionView.tag-100].objectForKey("code") as! String

        return code.componentsSeparatedByString(",").count
    }
    else
    {
        let code = codes2[collectionView.tag-200].objectForKey("code") as! String

        return code.componentsSeparatedByString(",").count
    }
}

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell
{
    let cell = collectionView.dequeueReusableCellWithReuseIdentifier("code", forIndexPath: indexPath) as! ImageCodeCollectionViewCell

    // Read that this should help for GPU
    cell.layer.shouldRasterize = true
    cell.layer.rasterizationScale = UIScreen.mainScreen().scale

    var codeLength:String! = ""

    if(collectionView.tag < 100)
    {
        codeLength = self.codes0[collectionView.tag].objectForKey("code") as! String
    }
    else if(collectionView.tag < 200)
    {
        codeLength = self.codes1[collectionView.tag-100].objectForKey("code") as! String
    }
    else
    {
        codeLength = self.codes2[collectionView.tag-200].objectForKey("code") as! String
    }

    let cLength = codeLength.componentsSeparatedByString(",")

    if(indexPath.row <= cLength.count)
    {
        cell.imageCode.image = UIImage(named: cLength[indexPath.row])
    }

    return cell
}

My tableView looks like:

Here's the collectionView data source and delegate set

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
    let cell = tableView.dequeueReusableCellWithIdentifier("cheat") as! CodeTableViewCell

    cell.layer.shouldRasterize = true
    cell.layer.rasterizationScale = UIScreen.mainScreen().scale

    cell.setCollectionViewDataSourceDelegate(self, forRow: indexPath.row, forSection: indexPath.section)

    return cell
}

func tableView(tableView: UITableView, willDisplayCell cell: CodeTableViewCell, forRowAtIndexPath indexPath: NSIndexPath)
{
    switch indexPath.section
    {
    case 2:
        cell.name = codes2[indexPath.row].objectForKey("name") as! String

        cell.descript = ((codes2[indexPath.row].objectForKey("description") as! String).isEmpty ? "-" : codes2[indexPath.row].objectForKey("description") as! String)

    case 1:
        cell.name = codes1[indexPath.row].objectForKey("name") as! String

        cell.descript = ((codes1[indexPath.row].objectForKey("description") as! String).isEmpty ? "-" : codes1[indexPath.row].objectForKey("description") as! String)

    default:
        cell.name = codes0[indexPath.row].objectForKey("name") as! String

        cell.descript = ((codes0[indexPath.row].objectForKey("description") as! String).isEmpty ? "-" : codes0[indexPath.row].objectForKey("description") as! String)
    }
}
Mat0
  • 1,095
  • 11
  • 27
  • Going by one look of the code,i think, its due to to many checks in the cellForRow... method. – Bista Sep 12 '16 at 14:43

1 Answers1

1

From looking briefly at your code, it seams like you would be fine with only an UICollectionView setup that makes use of UICollectionReusableView as headers. That way all the collectionViews would reuse the same cells and you don't have to layout the collectionViews each time a UITableViewCell becomes visible.

Interface Builder setup

Also you might consider storing the results of operations such as code.componentsSeparatedByString(",").count in separate variables, and only calculate it once your data is changed.

Aerows
  • 750
  • 6
  • 21
  • Yes I understand but since I have to use UICollectionReusableView as headers wouldn't I have to create a custom one if I need "global" headers to stick below navigationBar? – Mat0 Sep 12 '16 at 20:12
  • I see. I must say I mist that in my first look at your setup. There are ways of doing this, as referred in [this post](http://stackoverflow.com/a/33960962/2614339), how ever you would have to implement the intermediate headers as `custom cells`. Before trying anything else, have you tried loading your **images** on a *background thread*? – Aerows Sep 12 '16 at 21:48
  • Doesn't UIImage along with anything UI related has to be set on the main thread? Since I'm not downloading anything but only assinging the image this shouldn't be a problem? – Mat0 Sep 13 '16 at 16:22
  • You are right that the updating of the UI has to be done on the _main thread_, but the line `cell.imageCode.image = UIImage(named: cLength[indexPath.row])` is both loading the image, and then assigning it to the cell. Try to comment that part out and see if you experience any improvement. If you do, the following adjustment might be helpful: `dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ let image = UIImage(named: cLength[indexPath.row]) dispatch_async(dispatch_get_main_queue(), ^{ cell.imageCode.image = image }) })` – Aerows Sep 13 '16 at 21:20
  • I've tried that and for iOS 10 it works great but not for devices below? – Mat0 Sep 14 '16 at 14:52
  • Is that a question if it works for lower versions or why it is not working for lower versions? If the second, what is not working? – Aerows Sep 14 '16 at 15:38
  • I'm wondering why fps can vary that much. On an iPhone 6 with iOS 9 it runs with 33 fps, but for the same device yet with iOS 10 it runs with 59-60 fps? – Mat0 Sep 14 '16 at 18:10