NSMutableAttributedString initWithData:在旋转时导致EXC_BAD_ACCESS

我在tableview显示不同类型的内容,并使用不同的自定义方法在heightForRowAtIndexPath计算每个单元格的高度。

其中一个自定义方法意味着在NSMutableAttributedString转换一些html,然后计算此NSMutableAttributedString的高度。
对于html转换,我使用新的initWithData:方法。

一切都很完美,除非我旋转屏幕=>我每次都有一个exc_bad_access。

使用Instruments / Zombies,我已经能够找到错误,事实上它就是这个initWithData: .

(当我删除此方法并使用initWithString创建“简单” NSMutableAttributedString时,我可以根据需要更改方向,不再crash )。

知道为什么吗?

(顺便说一句,我的项目使用ARC)


Instrument / Zombie截图: 在此处输入图像描述


heightForRowAtIndexPath调用的自定义方法:

<UtilitiesForFrontEndUI heightForFacebookAttributedText :>

 +(CGFloat)heightForFacebookAttributedText:(NSString *)attributedText withWidth:(CGFloat)width { NSAttributedString *formatedText = [self formatRawFacebookContentForFrontEndRichTextContents:attributedText]; CGRect rect= [formatedText boundingRectWithSize:CGSizeMake(width, 1000) options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading context:nil]; return ceilf(rect.size.height); } 

使用initWithData进行html到NSMutableAttributedString转换的自定义方法:

<UtilitiesForFrontEndUI formatRawFacebookContentForFrontEndRichTextContents: >

 +(NSAttributedString *)formatRawFacebookContentForFrontEndRichTextContents:(NSString *)stringToFormat { // THIS GENERATE EXC_BAD_ACCESS ON DEVICE ROTATION (WORKS IF NO ROTATION) NSData *dataContent = [stringToFormat dataUsingEncoding:NSUTF8StringEncoding]; NSMutableAttributedString *richTxtContent = [[NSMutableAttributedString alloc] initWithData:dataContent options:@{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,NSCharacterEncodingDocumentAttribute: [NSNumber numberWithInt:NSUTF8StringEncoding]} documentAttributes:nil error:nil]; NSRange myRange; myRange.location = 0; myRange.length = richTxtContent.length; [richTxtContent addAttributes:[self commonAttributesForFrontEndRichText] range:myRange]; return richTxtContent; } 

如果我用一个简单的initWithString替换initWithData,则不再使用exc_bad_access

 +(NSAttributedString *)formatRawFacebookContentForFrontEndRichTextContents:(NSString *)stringToFormat { // THIS WORKS (NO MORE ROTATION CRASH) NSMutableAttributedString *richTxtContent = [[NSMutableAttributedString alloc]initWithString:stringToFormat]; NSRange myRange; myRange.location = 0; myRange.length = richTxtContent.length; [richTxtContent addAttributes:[self commonAttributesForFrontEndRichText] range:myRange]; return richTxtContent; } 

我的应用程序中发生了类似的情况。

[NSMutableAttributedString initWithData:]可能需要很长时间才能返回,尤其是对于大输入。 我的猜测是,当这个调用正在执行时,UIKit旋转处理代码需要运行,但是,由于你的主线程卡在initWithData:调用上,所以事情变得有点不对劲。

尝试将解析调用远离主线程,以便它不会阻止它:

 +(NSAttributedString *)formatRawFacebookContentForFrontEndRichTextContents:(NSString *)stringToFormat completion:(void (^)(NSAttributedString *))completion { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ NSData *dataContent = [stringToFormat dataUsingEncoding:NSUTF8StringEncoding]; NSMutableAttributedString *richTxtContent = [[NSMutableAttributedString alloc] initWithData:dataContent options:@{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,NSCharacterEncodingDocumentAttribute: [NSNumber numberWithInt:NSUTF8StringEncoding]} documentAttributes:nil error:nil]; NSRange myRange; myRange.location = 0; myRange.length = richTxtContent.length; [richTxtContent addAttributes:[self commonAttributesForFrontEndRichText] range:myRange]; dispatch_async(dispatch_get_main_queue(), ^{ if (completion) completion(richTxtContent); }) }); } 

当您的旋转发生时,也可能会释放与您的方法相关的某些对象,从而导致EXC_BAD_ACCESS。 你必须对- (void)dealloc和rotation方法进行一些调试才能看到发生了什么。

另一篇相关文档如下:

多核注意事项:自OS X v10.4起,NSAttributedString已将WebKit用于HTML文档的所有导入(但不用于导出)。 因为WebKit文档加载不是线程安全的,所以在后台线程上使用它并不安全。 对于在OS X v10.5及更高版本上链接的应用程序,如果NSAttributedString在除主线程之外的任何文件上导入HTML文档,则通过performSelectorOnMainThread:withObject:waitUntilDone:将WebKit的使用传输到主线程。 这使得操作线程安全,但它要求主线程以其中一种常见模式执行运行循环。 通过将标准用户默认NSRunWebKitOnAppKitThread的值设置为YES(无论链接如何获取新行为)或NO(无论链接如何获取旧行为),都可以覆盖此行为。

资源