Вопрос

I have custom UICollectionViewCell subclass where I draw with clipping, stroking and transparency. It works pretty well on Simulator and iPhone 5, but on older devices there is noticeable performance problems.

So I want to move time-consuming drawing to background thread. Since -drawRect method is always called on the main thread, I ended up saving drawn context to CGImage (original question contained code with using CGLayer, but it is sort of obsolete as Matt Long pointed out).

Here is my implementation of drawRect method inside this class:

-(void)drawRect:(CGRect)rect {

    CGContextRef ctx = UIGraphicsGetCurrentContext();
    if (self.renderedSymbol != nil) {
        CGContextDrawImage(ctx, self.bounds, self.renderedSymbol);
    }
}

Rendering method that defines this renderedSymbol property:

- (void) renderCurrentSymbol {

    [self.queue addOperationWithBlock:^{

// creating custom context to draw there (contexts are not thread safe)
        CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
        CGContextRef ctx = CGBitmapContextCreate(nil, self.bounds.size.width, self.bounds.size.height, 8, self.bounds.size.width * (CGColorSpaceGetNumberOfComponents(space) + 1), space, kCGImageAlphaPremultipliedLast);
        CGColorSpaceRelease(space);

// custom drawing goes here using 'ctx' context

// then saving context as CGImageRef to property that will be used in drawRect
        self.renderedSymbol = CGBitmapContextCreateImage(ctx);

// asking main thread to update UI    
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            [self setNeedsDisplayInRect:self.bounds];
        }];

        CGContextRelease(ctx);

    }];
}

This setup works perfectly on main thread, but when I wrap it with NSOperationQueue or GCD, I'm getting lots of different "invalid context 0x0" errors. App doesn't crash itself, but drawing doesn't happen. I suppose there is a problem with releasing custom created CGContextRef, but I don't know what to do about it.

Here's my property declarations. (I tried using atomic versions, but that didn't help)

@property (nonatomic) CGImageRef renderedSymbol;
@property (nonatomic, strong) NSOperationQueue *queue;
@property (nonatomic, strong) NSString *symbol; // used in custom drawing

Custom setters / getters for properties:

-(NSOperationQueue *)queue {
    if (!_queue) {
        _queue = [[NSOperationQueue alloc] init];
        _queue.name = @"Background Rendering";
    }
    return _queue;
}   
-(void)setSymbol:(NSString *)symbol {
    _symbol = symbol;
    self.renderedSymbol = nil;
    [self setNeedsDisplayInRect:self.bounds];
}

-(CGImageRef) renderedSymbol {
    if (_renderedSymbol == nil) {
        [self renderCurrentSymbol];
    }
    return _renderedSymbol;
}

What can I do?

Это было полезно?

Решение 2

Issue solved by using amazing third party library by Mind Snacks — MSCachedAsyncViewDrawing.

Другие советы

Did you notice the document on CGLayer you're referencing hasn't been updated since 2006? The assumption you've made that CGLayer is the right solution is incorrect. Apple has all but abandoned this technology and you probably should too: http://iosptl.com/posts/cglayer-no-longer-recommended/ Use Core Animation.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top