Sanjeet Suhag Sanjeet Suhag - 4 months ago 21
Swift Question

My CoreGraphics code is working really slowly. How can I make this custom UIScrollView perform better?

I made a custom class that creates a sort of timeline that is meant to be scrolled horizontally. Here's the code for my custom

UIScrollView
:

import UIKit

struct DataPoint {
var fillColor: UIColor = UIColor.grayColor()

init(color: UIColor) {
fillColor = color
}
}

@IBDesignable
class MyView: UIScrollView {

@IBInspectable var lineColor: UIColor = UIColor.grayColor()
@IBInspectable var lineHeight: CGFloat = 65
@IBInspectable var lineWidth: CGFloat = 15
@IBInspectable var lineGap: CGFloat = 25
@IBInspectable var lineCount: Int = 0

var dataPoints = [DataPoint(color: UIColor.greenColor()), DataPoint(color: UIColor.blueColor())]

override init(frame: CGRect) {
super.init(frame: frame)
setupValues()

}

required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupValues()
//fatalError("init(coder:) has not been implemented")
}

func setupValues() {

self.contentSize = CGSize(width: self.frame.width * 2, height: self.frame.height)

self.backgroundColor = UIColor.whiteColor()
self.lineCount = Int(self.frame.width / lineGap)
}

override internal func layoutSubviews() {
super.layoutSubviews()
self.setNeedsDisplay()
self.layoutIfNeeded()
}

override func drawRect(rect: CGRect) {

let ctx = UIGraphicsGetCurrentContext()
CGContextSaveGState(ctx)

for i in 0...lineCount {

let start = CGPoint(x: CGFloat(i) * lineGap, y: self.frame.height)
let end = CGPoint(x: CGFloat(i) * lineGap, y: self.frame.height - lineHeight)

drawLine(from: start, to: end, color: UIColor.grayColor())

if i % (lineCount / (dataPoints.count + 2)) == 0 && i != 0 && i != lineCount {
drawPoint(at: end, radius: 5, color: UIColor.orangeColor())
}
}

CGContextRestoreGState(ctx)
}

func drawLine(from start: CGPoint, to end: CGPoint, color: UIColor) {

let path = UIBezierPath()
path.moveToPoint(start)
path.addLineToPoint(end)

let shapeLayer = CAShapeLayer()
shapeLayer.path = path.CGPath
shapeLayer.strokeColor = color.CGColor
shapeLayer.lineWidth = 1

self.layer.addSublayer(shapeLayer)
}

func drawPoint(at center: CGPoint, radius: CGFloat, color: UIColor) {

let path = UIBezierPath(arcCenter: center, radius: radius, startAngle: CGFloat(0), endAngle: CGFloat(M_PI * 2), clockwise: true)

let shapeLayer = CAShapeLayer()
shapeLayer.path = path.CGPath
shapeLayer.fillColor = color.CGColor
shapeLayer.strokeColor = UIColor.blackColor().CGColor
shapeLayer.lineWidth = 0.5

self.layer.addSublayer(shapeLayer)
}
}


On my device and on the simulators, this is extremely slow and laggy. What exactly am I doing wrong here ? And what steps can I take to achieve a solid 60fps while scrolling ?

Answer

Hello I found your problem, your problem is

override internal func layoutSubviews() {
    super.layoutSubviews()
    self.setNeedsDisplay()
    self.layoutIfNeeded()
}

you are accidentally in a never-ending paint loop

replace this by this

override internal func layoutSubviews() {
    super.layoutSubviews()
}

or remove at all

I hope this Helps you, for me works great

Comments