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

时间:2014-05-19 02:43:18

标签: ios multithreading uikit core-text

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

我正在做

UIGraphicsPushContext()
[NSString drawInRect:]
UIGraphicsPopContext()

代码工作正常,但有时当我同时在主线程上绘图时,它会在drawInRect中崩溃。

我尝试使用NSAttributedString,如下所示: UIStringDrawing methods don't seem to be thread safe in iOS 6。但是[NSAttributedString drawInRect:]似乎不会出于某种原因在我的后台线程上呈现任何内容。主线程似乎工作正常。

我一直在考虑使用Core Text,但看起来Core Text也有类似的问题:CoreText crashes when run in multiple threads

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

更新 如果我运行此代码,它几乎会立即在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();

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

更新 这似乎只在iOS 6.1上崩溃,但似乎在iOS 7.1上运行良好。

2 个答案:

答案 0 :(得分: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];

});

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

答案 1 :(得分:0)

根据Apple's NSString UIKit Additions Reference[NSString drawInRect:...]是从应用的主要线程调用 必须 的方法之一(查看“概述” “该文件的一部分)。它说:

  

此类扩展中描述的方法必须在您的   应用程序的主要线程。

然后,任何更新UI 的内容都总是在主线程上......当然有些东西可能会出现在后台线程上(例如包括字符串和图像绘制 - { {3}})。

最后,see this related question and answersother people have reported problems trying to draw on background threads using "UIGraphicsPushContext"),因此iOS 6仍然存在问题。