如何在iOS中的后台线程上绘制文本?

Lev*_*Lev 1 multithreading uikit core-text ios

我需要在后台线程上绘制文本以将其保存为图像.

我正在做

UIGraphicsPushContext()
[NSString drawInRect:]
UIGraphicsPopContext()
Run Code Online (Sandbox Code Playgroud)

代码工作正常,但有时它在drawInRect中崩溃,当我也在同时绘制主线程时.

我尝试使用NSAttributedString,如下所示: UIStringDrawing方法似乎在iOS 6中不是线程安全的.但是[NSAttributedString drawInRect:]由于某种原因似乎没有在我的后台线程上呈现任何内容.主线程似乎工作正常.

我一直在考虑使用Core Text,但看起来Core Text也有类似的问题:CoreText在多个线程中运行时崩溃

是否有线程安全的方式来绘制文本?

更新: 如果我运行此代码,它几乎立即崩溃在drawInRect与EXC_BAD_ACCESS:

   dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{

      UIGraphicsBeginImageContextWithOptions(CGSizeMake(100, 100), NO, 0);
      UIFont* font = [UIFont systemFontOfSize:14.0f];

      for (int i = 0; i < 100000000; i++) {
         [@"hello" drawInRect:CGRectMake(0, 0, 100, 100) withFont:font];
      }

      UIGraphicsEndImageContext();
   });

   UIGraphicsBeginImageContextWithOptions(CGSizeMake(100, 100), NO, 0);
   UIFont* font = [UIFont systemFontOfSize:12.0f];

   for (int i = 0; i < 100000000; i++) {
      [@"hello" drawInRect:CGRectMake(0, 0, 100, 100) withFont:font];
   }

   UIGraphicsEndImageContext();
Run Code Online (Sandbox Code Playgroud)

如果我删除UIFont并只绘制没有字体的文本,它可以正常工作.

更新: 这似乎只在iOS 6.1上崩溃,但似乎在iOS 7.1上正常工作.

Som*_*Guy 6

从iOS6(可能更早)开始,您可以在不同的线程上使用这些方法,只要您在同一个线程上使用UIGraphicsBeginImageContext ...创建了新的上下文.

drawRect:方法默认为其自己的线程的当前上下文.

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{

    UIGraphicsBeginImageContextWithOptions(CGSizeMake(100, 100), NO, 0);

    UIFont* font = [UIFont systemFontOfSize:26];
    NSString* string = @"hello";
    NSAttributedString* attributedString = [[NSAttributedString alloc] initWithString:string attributes:@{NSFontAttributeName:font}];

    [attributedString drawInRect:CGRectMake(0, 0, 100, 100)];

    UIImage* image = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    [UIImagePNGRepresentation(image) writeToFile:@"/testImage.png" atomically:YES];

});
Run Code Online (Sandbox Code Playgroud)

在模拟器上运行它,它会将结果输出到硬盘的根目录.