asynchronous drawing and touches

2019-04-01 04:41发布

问题:

I have a draw area (UIView), where i draw within the CGContextRef.
Ofcourse i am catching touches to draw. While the drawRect method slowly draws lot's of existing objects the touches are not caught.
If i call drawing in drawRect in separate thread or with function "dispatch_async" it doesn't draw because it has no appropriate context.
I've seached a lot but found nothing.

dispatch_async(dispatch_get_main_queue(), ^{
    [_mainArea setNeedsDisplay];
});
  • these things do not help either.

What can i do? Can anybody help to catch touches and draw lots of objects simultainiously?

回答1:

When you're having problems keeping your graphics up to date, before you start getting into multithreading...

  1. You should remove all calls to display or setNeedsDisplay and replace them with setNeedsDisplayInRect:

  2. You should optimize your drawRect: method so that you're only redrawing the parts of the view that need it. You can get even more fancy in this method and ignore the rect argument from the method and obtain the raw rects being drawn from getRectsBeingDrawn:count:.

  3. If you're drawing moving objects, use CoreAnimation.

  4. If you have a lot of repeated objects, use CGLayerRefs

Calling setNeedsDisplay with a dispatch_async() won't make the view draw on another thread; all drawing happens in drawRect:, and drawRect: is always called by the main thread/queue.

UIGraphicsGetCurrentContext() is not thread safe. What you can do however is create a bitmap context in your async block, stroke and fill into that, and then get this context as a CGImageRef that can be comp'd into the CGContextRef (the one that's talking to the screen) running on the main thread. It would look something like this:

@implementation BGDrawingClass : UIVew {
    CGImageRef bgImage;
}

-(void)prepBGImage {

CGRect rect = TheRectISpendALotOfTimeIn();
dispatch_async(_myBGQueue,^{

        CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
        CGContextRef ctx = CGBitmapContextCreate(nil, rect.size.width, rect.size.height, 8, rect.size.width * (CGColorSpaceGetNumberOfComponents(space) + 1), space, kCGImageAlphaPremultipliedLast);
        CGColorSpaceRelease(space);

        /* do expensive drawing in this context */

        bgImage = CGBitmapContextCreateImage(ctx);

        dispatch_async(dispatch_get_main_queue(),^{ 
             [self setNeedsDisplayInRect:rect];
        });
    });
}

-(void)drawRect:(NSRect)rect {
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    /* do drawing behind this ... */
    if (CGRectIntersectsRect(rect, TheRectISpendALotOfTimeIn()) {
        CGContextDrawImage(ctx, TheRectISpendALotOfTimeIn(), bgImage);
    }
    /* do drawing in front of this */
}
@end