1

I've written a render function that is called every 1/60 of a second. It's shown below. Essentially, it renders 40 lines in radial pattern that uses sine. It looks like this https://i.sstatic.net/HPwOd.jpg. When I run it on my iPhone 6s with the debugger on, it shows that it is using around 60% of the CPU and it just makes the "high" battery usage level. This doesn't seem right to me, it's only 40 simple lines right?

Could I be doing this more efficiently? Should I try to use something else like CALayer or Metal for better performance? I'm a noob at this by the way.

func render() { tick += 0.01 let renderer = UIGraphicsImageRenderer(size: CGSize(width: 375, height: 667)) let img = renderer.image { ctx in let c = ctx.cgContext // Set background let background = CGRect(x: 0, y: 0, width: 375, height: 667) c.setFillColor(UIColor.black.cgColor) c.addRect(background) c.drawPath(using: .fillStroke) // Function to draw a line func line(p1:CGPoint, p2:CGPoint) { let line = CGRect(x: 0, y: 0, width: 200, height: 200) c.addLines(between: [p1,p2]) c.drawPath(using: .fillStroke) } // Draw lines c.setStrokeColor(UIColor.white.cgColor) c.setLineWidth(1) c.setLineCap(CGLineCap.round) for i in 0...39 { let n:CGFloat = CGFloat(i) * CGFloat.pi/40 let d:CGFloat = sin(tick + CGFloat(i)*CGFloat.pi/5)*20 + 100 line(p1: CGPoint(x: d*cos(tick+n)+187.5, y: d*sin(tick+n)+333.5), p2: CGPoint(x: d*cos(tick+n+CGFloat.pi)+187.5, y: d*sin(tick+n+CGFloat.pi)+333.5)) } } imageView.image = img } 
5
  • while true { print("loop" } should be fast, it's only 1 line, right? Commented Nov 21, 2016 at 1:57
  • should probably use scenekit/gamekit or openGL to do this, i dont think UIGraphicsImageRenderer was designed to be used in this way Commented Nov 21, 2016 at 2:07
  • You are calling cos 2400 times per second and sin 3600 times per second as well as performing at least 16800 multiplications per second all just inside the for loop. Commented Nov 21, 2016 at 2:07
  • Your shape is symmetrical around 4 axes. You can calculate the coordinates for just 6 of the 40 lines the expensive way and draw the other 34 through simple reflections involving very simple math. Commented Nov 21, 2016 at 2:10
  • @rmaddy Thanks for the explanation that's interesting to consider. I experimented with removing some parts of the code like the sine or multiplication to see if it would help. I ended up removing the entire for loop so it was just the black square that was drawing every 1/60 second. Even with just the black background it still used over 50% of the CPU. Guess I'll try using OpenGL or Metal... Commented Nov 21, 2016 at 3:02

1 Answer 1

1

I think apptoach isn't good. When you want to display animated content you shouldn't redraw views. You should use CoreAnimation. The good news is its easy to implement. The bad news is it needs a little bit to learn. ;)

Some suggestions to your code:

  1. Some parts of your drawing seems to be constant. Thus souldn't redraw this again and again. Instead you can put it in a separate layer.
  2. As @rmaddy suggests you need many sinand cos computations. But these values should always be the same. So you can compute them once and cache them.
  3. You can implement the drawing inside in draw(in:), and use dynamic properties for all variable parts the code. You can use animations from CoreAnimation then to animate your drawing. Creating dynamic CA-properties in Swift is a litte bit tricky. (As far as I know you must annotate them with @NSManaged(!), and you must overwrite needsDisplay(forKey:) and return truefor them.).
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.