2014-05-19 39 views
0

我需要在後臺線程上繪製文本以將其保存爲圖像。如何在iOS的後臺線程上繪製文本?

我做

UIGraphicsPushContext() 
[NSString drawInRect:] 
UIGraphicsPopContext() 

的代碼工作正常,但有時在drawInRect崩潰時,我也同時繪製在主線程上。

我試着按照這裏建議的方式使用NSAttributedString: UIStringDrawing methods don't seem to be thread safe in iOS 6。但[NSAttributedString drawInRect:]似乎沒有渲染任何東西在我的後臺線程出於某種原因。主線程似乎工作正常,但。

我一直在想使用核心文本的,不過貌似核心文本也有類似的問題:CoreText crashes when run in multiple threads

有沒有繪製文本線程安全的方式?

UPDATE: 如果我運行這段代碼,它幾乎立即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,只是沒有繪製字體的文本,它工作正常。

UPDATE: 這似乎只崩潰在iOS 6.1,但似乎在iOS 7.1做工精細。

+0

我想要幫助解決問題,發佈實際的代碼給你的問題,並提供有關崩潰的細節。 – rmaddy

回答

5

由於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]; 

}); 

在模擬器上運行它,它會將結果輸出到硬盤驅動器的根目錄。

+0

我修改了代碼,以便在後臺和循環中的主線程上不斷調用drawInRect。一切都很好,但如果我使用[@「hello」drawInRect:CGRectMake(0,0,100,100)withFont:font],它會崩潰。請參閱我更新的帖子。 – Lev

+0

@Lev我看着你的循環示例,它因爲UIFont而崩潰,而不是drawInRect:方法。我已經更新了我的示例,使用帶有NSAttributedString的UIFont,而不是在大循環中使用iOS6進行測試,並且工作正常:) – SomeGuy

+0

我發現使用[@「hello」drawInRect時,它只會在iOS 6.1上崩潰: CGRectMake(0,0,100,100)withFont:font] – Lev

0

Apple's NSString UIKit Additions Reference[NSString drawInRect:...]是那些MUST從您的應用程序的主線程調用(看該文件的「概述」部分)的方法之一。它說:

此類擴展中描述的方法必須從您的 應用的主線程中使用。

話又說回來,任何更新UI 應該總是在主線程中......肯定有一些東西,可能是在後臺線程(例如包括串並描繪 - see this related question and answers)。

最後,other people have reported problems trying to draw on background threads using "UIGraphicsPushContext"at least with iOS 5.X),因此仍可能有問題與iOS 6

+0

那麼,有沒有辦法將文本呈現到後臺線程中的圖像上?如果我不能在後臺線程上使用NSString繪圖方法,那麼這個語句是什麼意思?:「字符串和圖像繪圖現在是線程安全的。」 – Lev