Рисование в контексте в фоновом потоке - PullRequest
4 голосов
/ 27 июня 2011

У меня есть UIView, который должен отображать некоторую информацию.Поскольку этот вид довольно сложен, а отрисовка занимает значительное время, я переместил его в фоновый поток, чтобы избежать блокировки основного потока.Когда рисование закончено, я отправляю обратно в основной поток, чтобы установить ImageView.

Следующий код выполняет рисование для меня, но я получаю некоторые случайные сбои.Обычно xcode указывает на [view release]; и говорит Thread 6: Program received signal: EXC_BAD_ACCESS

NSManagedObjectID *objectID = [self.managedObject objectID];
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
        dispatch_async(queue,^{
            NSManagedObjectContext *backgroundContext = [[NSManagedObjectContext alloc] init];
            [backgroundContext setPersistentStoreCoordinator:[[self.managedObject managedObjectContext] persistentStoreCoordinator]];
            NSManagedObject *mo = [backgroundContext objectWithID:objectID];
            CGImageRef resultImage;
            CGContextRef context;
            void *bitmapData;

    CGRect frame = self.frame;
    frame.origin = CGPointZero;

    CGColorSpaceRef colorSpace;
    CGSize canvasSize;
    int bitmapByteCount;
    int bitmapBytesPerRow;

    canvasSize = frame.size;
    CGFloat scale = [UIScreen instancesRespondToSelector:@selector(scale)] ? [[UIScreen mainScreen] scale] : 1.0f;
    canvasSize.width *= scale;
    canvasSize.height *= scale;

    bitmapBytesPerRow = (canvasSize.width * 4);
    bitmapByteCount = (bitmapBytesPerRow * canvasSize.height);

    //Create the color space
    colorSpace = CGColorSpaceCreateDeviceRGB();

    bitmapData = malloc( bitmapByteCount );

    //Check the the buffer is alloc'd
    if( bitmapData == NULL ){
        DLog(@"Buffer could not be alloc'd");
    }

    //Create the context
    context = CGBitmapContextCreate(bitmapData, canvasSize.width, canvasSize.height, 8, bitmapBytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast);
    CGContextClearRect(context, CGRectMake(0, 0, canvasSize.width, canvasSize.height));

    // Setup transformation
    CGContextSetInterpolationQuality(context, kCGInterpolationNone);
    CGContextTranslateCTM(context, 0.0f, canvasSize.height); 
    CGContextScaleCTM(context, scale, -scale);

    UIView *view = [[UIView alloc] initWithFrame:frame];
    [view setBackgroundColor:[UIColor clearColor]];

    UILabel *nameLabel = [[UILabel alloc] initWithFrame:CGRectMake(137, 5, 255, 30)];
    [nameLabel setFont:[UIFont fontWithName:@"Arial" size:22.0f]];
    [nameLabel setText:[mo valueForKey:@"name"]];
    [nameLabel setTextAlignment:UITextAlignmentRight];
    [view addSubview:nameLabel];
    [nameLabel release];
    nameLabel = nil;
    ... Creating 20 or so label/imageviews all use 'mo' for data access to the NSManagedObject.

    [view.layer renderInContext:context];
    [view release];
    view = nil;
    //Get the result image
    resultImage = CGBitmapContextCreateImage(context);
    UIImage *viewImage = [UIImage imageWithCGImage:resultImage scale:0.0 orientation:UIImageOrientationUp];
    dispatch_async(dispatch_get_main_queue(),^ {
        [dataImageView setImage:viewImage];
    });

    //Cleanup
    free(bitmapData);
    CGColorSpaceRelease(colorSpace);
    CGImageRelease(resultImage);  
    CGContextRelease(context);
}); 

Надеюсь, вы, ребята, можете мне помочь, потому что я не могу понять, как это сделать.Я попытался запустить его с NSZombieEnabled ДА, что несколько раз приводило к следующей ошибке в консоли -[UILabel hash]: message sent to deallocated instance 0x22841c00

1 Ответ

0 голосов
/ 27 июня 2011

Попробуйте выяснить этот возможный источник проблемы: когда вы создаете UILabel (s), вы добавляете их в UIView, а затем отпускаете их (это нормально), но вы также «обнуляете» их. Итак, на данный момент у вас есть UILabel, которая сохраняется UIView, но в то же время она указывает на ноль! Таким образом, в конце, когда вы отпускаете «view», он попытается освободить свои подпредставления, и, как только он встретит UILabel, которая сохранила count = 1, но он был равен нулю, он получит исключение «deallocated instance». Это может продемонстрировать, почему отладчик останавливается на [view release] и почему NSZombieEnabled жалуется на попытку освободить UILabel: он видит его таким же освобожденным, как указатель указывает на ноль. Возможное решение: удалите оператор nameLabel = nil.

...