Drawing a grid in UIScrollView's subview alloc

2019-02-11 07:32发布

问题:

I'm trying to create a UIView in UIScrollView that contains just a simple grid (lines as rows and columns) drown by UIBezierPath or using the CG functions. The problem is, that when I have larger content size of the UIScrollView (as well as the larger subview), during the drawing of the grid huge amount of memory is allocated (50MB or more).

UIViewController which includes just UIScrollView over whole scene - adding subview in viewDidLoad:

@interface TTTTestViewController()

@property (weak, nonatomic) IBOutlet UIScrollView *scrollView;

@end

@implementation TTTTestViewController

-(void)viewDidLoad
{
    [super viewDidLoad];

    // create the subview
    TTTTestView *testView = [[TTTTestView alloc] init];
    [self.scrollView addSubview:testView];

    //set its properties
    testView.cellSize = 50;
    testView.size = 40;

    // set the content size and frame of testView by the properties
    self.scrollView.contentSize = CGSizeMake(testView.cellSize * testView.size, testView.cellSize * testView.size);
    testView.frame = CGRectMake(0, 0,  self.scrollView.contentSize.width, self.scrollView.contentSize.height);

    // let it draw the grid
    [testView setNeedsDisplay];
}

@end

Inner view that just draw the grid using UIBezierPath/CG functions - depends on properties size(rows/columns count) and cellSize (width/height of one cell in grid):

#define GRID_STROKE_WIDTH 2.0

@implementation TTTTestView

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        self.backgroundColor = [UIColor clearColor];
    }
    return self;
}

- (void)drawRect:(CGRect)rect
{
    [super drawRect:rect];
    [self drawGrid];
}

-(void)drawGrid
{
    UIBezierPath *path = [[UIBezierPath alloc] init];

    for (int i = 1; i < self.size; i++) {
            //draw row line
        [path moveToPoint:CGPointMake(0, self.cellSize * i)];
        [path addLineToPoint:CGPointMake(self.bounds.size.width, self.cellSize * i)];
            // draw column line
        [path moveToPoint:CGPointMake(self.cellSize * i, 0)];
        [path addLineToPoint:CGPointMake(self.cellSize * i , self.bounds.size.height)];
    }
    [path setLineWidth:GRID_STROKE_WIDTH];
    [[UIColor blackColor] setStroke];
    [path stroke];
    /*
     CGContextRef context = UIGraphicsGetCurrentContext();

     CGContextSetLineWidth(context, GRID_STROKE_WIDTH);
     CGContextSetStrokeColorWithColor(context, [UIColor blackColor].CGColor);

     for (int i = 1; i < self.size; i++) {
     //draw row line
     CGContextMoveToPoint(context, 0, self.cellSize * i );
     CGContextAddLineToPoint(context, self.bounds.size.width, self.cellSize * i);
     // draw column line
     CGContextMoveToPoint(context, self.cellSize * i , 0);
     CGContextAddLineToPoint(context, self.cellSize * i , self.bounds.size.height);
     }

     CGContextStrokePath(context);
     */
}

@end

Example1: self.size is 10, self.cellSize is 200 => contentSize is 2000x2000 points as well as frame of inner view => 18 lines are drown and it allocates ~60MB memory

Example2: self.size is 30, self.cellSize is 70 => contentSize is 2100x2100 points as well as frame of inner view => 58 lines are drown and it allocates ~67MB memory

These memory numbers I can see when debug the drawing method. No matter how I draw the lines, huge amount of memory is allocated when calling [path stroke] resp. CGContextStrokePath(context). In instruments I can see the biggest memory allocation at line:

12658 0x10200000 VM: CoreAnimation 00:04.092.149 • 67,29 MB QuartzCore CA::Render::Shmem::new_shmem(unsigned long)

I'm quite new in iOS programming and I was searching the solution everywhere and I still have no idea :-/ Can anyone please help me find some explanation what is going on here? Thanks :)

回答1:

After asking on apple developer forum, I find out, that this is properly allocated memory in fact. It's because any view that uses -drawRect: to draw will use memory on the order of (bounds.size.width * bounds.size.height * contentScale * contentScale * 4) bytes.

The simplest way to create a grid that avoids that is to use add a view for each line and use the view's backgroundColor property to color the view. This will use hardly any memory because the view's (which can be plain UIViews) don't need to call -drawRect:, and thus won't use extra memory to store the results of your drawing.