Skip to content

Instantly share code, notes, and snippets.

@iCarambaa
Last active March 17, 2017 13:08
Show Gist options
  • Save iCarambaa/204fe7599dd59e3b378eb91f65fba4d6 to your computer and use it in GitHub Desktop.
Save iCarambaa/204fe7599dd59e3b378eb91f65fba4d6 to your computer and use it in GitHub Desktop.
setNeedsDisplay grows linear with drawRect:, rdar://31113056
import UIKit
import PlaygroundSupport
// This playground compares the time spend in `setNeedsDisplay` to the time spend in `draw(rect:)`
// From the documentation, `setNeedsDisplay` should return in constant time but as you see here
// it grows linear with the time needed in `draw(rect)`.
// to compare for yourself, observe the variables `timeInSetNeedsDisplay` and `timeInDrawRect` and start drawing points by panning in
// the live view
final class PointView: UIView {
private var dataPoints: [CGPoint] = []
override init(frame: CGRect) {
super.init(frame: frame)
dataPoints.reserveCapacity(1000)
isOpaque = false
self.backgroundColor = UIColor.clear
contentMode = .redraw
}
required init(coder: NSCoder) {
fatalError("NSCoding not supported")
}
public func addDataPoint(_ point: CGPoint){
dataPoints.append(point)
let s = CFAbsoluteTimeGetCurrent()
self.setNeedsDisplay()
// Time spend in `setNeedsDisplay`
let timeInSetNeedsDisplay = CFAbsoluteTimeGetCurrent() - s
}
override func draw(_ rect: CGRect) {
let time = CFAbsoluteTimeGetCurrent()
drawPoints(rect)
// Time spend in `draw(rect:)`
let timeInDrawRect = CFAbsoluteTimeGetCurrent() - time
}
private func drawPoints(_ rect: CGRect){
let context = UIGraphicsGetCurrentContext()!
context.saveGState()
let circle = UIBezierPath(ovalIn: CGRect(origin: .zero, size: CGSize(width: 3, height: 3)))
circle.lineWidth = 0
UIColor.red.setFill()
for point in dataPoints {
context.saveGState()
context.translateBy(x: point.x, y: point.y)
circle.fill()
context.restoreGState()
}
context.restoreGState()
}
}
final class GraphViewController: UIViewController {
var pointView: PointView!
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.white
pointView = PointView(frame: self.view.bounds)
pointView.autoresizingMask = [.flexibleHeight, .flexibleWidth]
view.addSubview(pointView)
let pan = UIPanGestureRecognizer(target: self, action: #selector(gestureRecognizerDidFire(gestureRecognizer:)))
pointView.addGestureRecognizer(pan)
}
@objc private func gestureRecognizerDidFire(gestureRecognizer: UIPanGestureRecognizer){
switch(gestureRecognizer.state){
case .began, .changed:
pointView.addDataPoint(gestureRecognizer.location(in: pointView))
default: break
}
}
}
PlaygroundPage.current.liveView = GraphViewController()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment