Last active
March 17, 2017 13:08
-
-
Save iCarambaa/204fe7599dd59e3b378eb91f65fba4d6 to your computer and use it in GitHub Desktop.
setNeedsDisplay grows linear with drawRect:, rdar://31113056
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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