0

I'm making an app that draws elementary cellular automata. Currently I'm using UIBezierPath to draw the cells in a custom UIView:

 var path : UIBezierPath
    for (heightIndex, row) in stateMatrix!.enumerate() {
        for (widthIndex, cell) in row!.enumerate() {

            let myRect = CGRect(x: cellWidth * CGFloat(widthIndex), y: cellWidth * CGFloat(heightIndex), width: cellWidth, height: cellWidth)

            path = UIBezierPath(rect: myRect)
            if cell == "x" {
                Constants.OnColor.setFill()
                Constants.OnColor.setStroke()
            } else {
                Constants.OffColor.setFill()
                Constants.OffColor.setStroke()
            }
            path.fill()
            path.stroke()
        }
    }

The grid I'm drawing is approximately n * 6n cells. This code works fine when n is small, but it obviously doesn't scale well (on my iPhone 4s, with n = 150, it takes about a minute and a half). Clearly there must be a better way to do this than calling UIBezierPath a few hundred thousand times. What would be a better way to approach this?

c_booth
  • 2,185
  • 1
  • 13
  • 22

1 Answers1

1

Why are you using UIBezierPath? With 150 * 150 squares it is normal to take such time to handle it (https://en.wikipedia.org/wiki/Bézier_curve). Instead of UIBezierPath you can use CoreGraphics calls. Here is an example in Obj-C :

int side = 100; // number of squares in one side
int delta = 300 / side;

for (int i = 0; i < side; i++) {
    for (int j = 0; j < side; j++) {
        CGRect rectangle = CGRectMake(delta * i, delta * j, delta, delta);
        CGContextRef context = UIGraphicsGetCurrentContext();
        CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 0.5);
        CGContextSetRGBStrokeColor(context, 0.0, 0.0, 0.0, 0.5);
        CGContextFillRect(context, rectangle);
        CGContextStrokeRect(context, rectangle);
    }
}

This example takes less than 0.1 second to draw this number of squares.

2016-01-09 23:55:02.677
2016-01-09 23:55:02.741
shpasta
  • 1,913
  • 15
  • 21
  • Thanks for the response. I've implemented your code (in Swift) into my loop above in place of the UIBezierPath, but it still takes well over a minute on my 4S. – c_booth Jan 10 '16 at 13:58
  • I have created tiny Swift project with simple view example for you. Can you please run it and paste received logs here. https://www.dropbox.com/sh/gcnv7m8k93lnz2m/AAAGFewgc0-iz7lzSGbJ6B5Oa?dl=0 – shpasta Jan 11 '16 at 01:40
  • 2016-01-12 16:58:59.352 TestDraw[1520:493564] Start drawing 2016-01-12 16:59:00.149 TestDraw[1520:493564] Finish drawing - I will start looking for other bottlenecks – c_booth Jan 12 '16 at 08:01
  • Yes. Drawing is pretty fast here, and reason of slow performance is in some place in your project. Try to use Instruments to find it ( XCode > Open Developer Tool > Instruments ) – shpasta Jan 12 '16 at 16:20