(iphone) есть вызов функции (связанный с UIImage), который я не должен делать в неосновном потоке здесь? - PullRequest
0 голосов
/ 22 апреля 2011

Я пытаюсь создать UIImage из фонового потока.
Интересно, не следует ли использовать какой-либо вызов, который я здесь использую, в фоновом режиме.
Спасибо

// defined below 
CGContextRef context = CreateARGBBitmapContext(entireRect.size);                                                                                                                                                                                                        

CGContextDrawImage(context, rect, originalImage.CGImage);                                                                                                                                                                                                                    

CGImageRef imageRef = CGBitmapContextCreateImage(context);                                                                                                                                                                                                                  
UIImage* img = [UIImage imageWithCGImage: imageRef];                                                                                                                                                                                                                  
CGImageRelease(imageRef);                                                                                                                                                                                                                  

CGContextRelease(context);                                                                                                                                                                                                                                     

return img;        

Где CreateARGBBitmapContext определяется, как показано ниже.

CGContextRef CreateARGBBitmapContext(CGSize size)
{
    CGContextRef    context = NULL;
    CGColorSpaceRef colorSpace;
    void *          bitmapData;
    int             bitmapByteCount;
    int             bitmapBytesPerRow;

    // Get image width, height. We'll use the entire image.                                                                                                                                                                                                                   
    size_t pixelsWide = size.width;
    size_t pixelsHigh = size.height;

    // Declare the number of bytes per row. Each pixel in the bitmap in this                                                                                                                                                                                                  
    // example is represented by 4 bytes; 8 bits each of red, green, blue, and                                                                                                                                                                                                
    // alpha.                                                                                                                                                                                                                                                                 
    bitmapBytesPerRow   = (pixelsWide * 4);
//  bitmapBytesPerRow = (int) round( pow( 2.0, trunc( log((double) bitmapBytesPerRow) / log(2.0) ) + 1.0 ) );                                                                                                                                                                 
    bitmapByteCount     = (bitmapBytesPerRow * pixelsHigh);

    // Use the generic RGB color space.                                                                                                                                                                                                                                       
    colorSpace = CGColorSpaceCreateDeviceRGB();

    if (colorSpace == NULL)
    {
        fprintf(stderr, "Error allocating color space\n");
        return NULL;
    }

    // Allocate memory for image data. This is the destination in memory                                                                                                                                                                                                      
    // where any drawing to the bitmap context will be rendered.                                                                                                                                                                                                              
    NSMutableData* mutableData = [NSMutableData dataWithLength: bitmapByteCount];
    bitmapData = [mutableData mutableBytes];
    if (bitmapData == NULL)
    {
        fprintf (stderr, "Memory not allocated!");
        CGColorSpaceRelease( colorSpace );
        return NULL;
    }

    // Create the bitmap context. We want pre-multiplied ARGB, 8-bits                                                                                                                                                                                                         
    // per component. Regardless of what the source image format is                                                                                                                                                                                                           
    // (CMYK, Grayscale, and so on) it will be converted over to the format                                                                                                                                                                                                   
    // specified here by CGBitmapContextCreate.                                                                                                                                                                                                                               
    context = CGBitmapContextCreate (bitmapData,
                                     pixelsWide,
                                     pixelsHigh,
                                     8,      // bits per component    
                                    bitmapBytesPerRow,
                                     colorSpace,
                                     kCGImageAlphaPremultipliedFirst);
    if (context == NULL)
    {
        fprintf (stderr, "Context not created!");
    }

    // Make sure and release colorspace before returning                                                                                                                                                                                                                      
    CGColorSpaceRelease( colorSpace );

    return context;
}

1 Ответ

0 голосов
/ 22 апреля 2011

Следующая строка должна быть в основном потоке:

UIImage* img = [UIImage imageWithCGImage: imageRef];      

Остальная часть кода выглядит так, как будто было бы нормально находиться в другом потоке.

Любое взаимодействие с UIKit должно быть в основном потоке. Вот почему создание UIImage (или даже что-то вроде установки изображения UIImageView) должно выполняться в основном потоке. К счастью, тяжелая работа, такая как загрузка изображения или, возможно, даже рисование, как вы делаете, может быть выполнена в отдельном потоке. Затем вы возвращаетесь в основной поток, чтобы создать UIImage.

Используя Grand Central Dispatch и некоторые блоки, следующий код может работать для вас:

</p>

<code>    dispatch_queue_t drawingQueue = dispatch_queue_create("Drawing image", NULL);
    dispatch_async(drawingQueue, ^{
        CGContextRef context = CreateARGBBitmapContext(entireRect.size);                                                                                                                                                                                                                
        CGContextDrawImage(context, rect, originalImage.CGImage);                                                                                                                                                                                                                           
        CGImageRef imageRef = CGBitmapContextCreateImage(context);           
        dispatch_async(dispatch_get_main_queue(), ^{
            UIImage* img = [UIImage imageWithCGImage: imageRef];                                                                                                                                                                                                                  
            CGImageRelease(imageRef); 
        });
    });
    dispatch_release(drawingQueue);
</code>

Если вы не знакомы с Grand Central Dispatch, попробуйте поискать его в Google. Боюсь, я не знаю хорошего учебника для него. Надеюсь, что это полезно.

ИСПРАВЛЕНИЕ:

Мой ответ выше неверен. UIImage МОЖЕТ быть создан в главном потоке.

Хотя большая часть взаимодействия с UIKit должна выполняться в основном потоке, есть несколько исключений, включая UIImage, UIColor, UIFont и Core Graphics. Это все потокобезопасные.

(Обратите внимание, что я считаю, что UIImageView не является потокобезопасным. Так что, если бы вы установили изображение UIImageView, вам пришлось бы вернуться к основному потоку. Вариант приведенного выше кода все равно будет полезен для взаимодействия с другие объекты UIKit, и в этом случае не должны наносить никакого ущерба - кроме ненужных усложняющих вещей.)

...