Можно ли использовать Quartz 2D для создания UIImage на другой нити?


Я хочу переместить некоторый код, который занимает пару секунд, чтобы сгенерировать UIImage в другом потоке, но я получаю контекстную ошибку при использовании

    UIGraphicsBeginImageContextWithOptions(size,false,0);

Перед вызовом диспетчера для создания образа, говорящего "недопустимый контекст 0x0" для каждой операции, которую я пытаюсь сделать. Возможно ли это вообще?

3 3

3 ответа:

Что нового в iOS: iOS 4.0 говорит это:

  • рисование в графическом контексте в UIKit теперь потокобезопасно. Конкретно:
      Процедуры, используемые для доступа к графическому контексту и управления им, теперь могут корректно обрабатывать контексты, находящиеся в разных потоках.
  • рисование строк и изображений теперь потокобезопасно.
  • теперь безопасно использовать объекты цвета и шрифта в нескольких потоках.

Похоже, вы пробовали что-то вроде этого:

UIGraphicsBeginImageContextWithOptions(size,false,0);
dispatch_async(someQueue, ^{
    [UIColor.whiteColor setFill];
    UIRectFill(0, 0, 20, 20);
    dispatch_async(dispatch_get_main_queue(), ^{
        UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        self.imageView.image = image;
    });
};

Это не сработает, потому что каждый поток имеет свой собственный стек графических контекстов (начиная с iOS 4.0). Вам нужно сделать это так:

dispatch_async(someQueue, ^{
    UIGraphicsBeginImageContextWithOptions(size,false,0);
    [UIColor.whiteColor setFill];
    UIRectFill(0, 0, 20, 20);
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    dispatch_async(dispatch_get_main_queue(), ^{
        self.imageView.image = image;
    });
};

Обновление

Документация для UIGraphicsBeginImageContextWithOptions и других графических функций UIKit теперь говорит

В iOS 4 и более поздних версиях вы можете вызвать эту функцию из любого потока вашего приложения.

Документация для UIColor говорит

Цветовые объекты являются неизменяемыми, поэтому их можно безопасно использовать из нескольких потоков в приложении.

Документация для UIFont говорит

Объекты шрифтов являются неизменяемыми, поэтому их можно безопасно использовать из нескольких потоков в приложении.

Однако , документация для UIKit NSString-чертежные дополнения говорит

Методы, описанные в этом расширении класса, должны использоваться из вашего основной поток приложения.

Поэтому вы должны Не попробовать что-то вроде [@"hello" drawAtPoint:CGPointZero withAttributes:attrs] из фонового потока.

Документы говорят:

Эту функцию следует вызывать только из основного потока приложения.

Поэтому вызывать его в другом потоке не очень хорошая идея.

Вместо этого можно попробовать использовать CoreGraphics и вызвать CGBitmapContextCreate().

Вы можете легко работать с помощью CGContext, чтобы создать CGImage, находясь во вторичном потоке.

Возвращаясь к основному потоку, создайте UIImage из CGImage. Обратите внимание, что UIImage является неизменяемым типом контейнера - это не должно приводить к глубокой копии данных изображения.