2013-12-22 55 views
13

我在tableview中显示不同类型的内容,并使用不同的自定义方法在heightForRowAtIndexPath中计算每个单元格的高度。NSMutableAttributedString initWithData:导致旋转的EXC_BAD_ACCESS

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

除了当我旋转屏幕时,所有的工作都很完美=>我每次都有一个exc_bad_access。

使用仪器/僵尸,我一直能找到错误,实际上它是这样的initWithData:。 (当我删除此方法并创建一个“简单”NSMutableAttributedStringinitWithString,我可以更改方向多少时间,我想要的,没有crash了)。

任何想法为什么?

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


仪器/僵尸截图: enter image description here


称为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; 
} 

如果我更换initWithData通过简单initWithString没有更多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; 
} 

回答

11

我有类似的情况发生在我的应用程序。

[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和旋转方法上进行一些调试才能看到发生了什么。

另一块相关文件如下:

多核方面的考虑:由于OS X 10.4,NSAttributedString对所有进口 使用的WebKit(但不包括出口)HTML文档。 由于WebKit文档加载不是线程安全的,因此在后台线程上使用它并不安全。对于在OS X v10.5和更高版本上链接的应用程序,如果NSAttributedString导入任何 (但主线程)上的HTML文档,则通过performSelectorOnMainThread:withObject:waitUntilDone:将WebKit的使用转移到主线程 。这个 使操作线程安全,但它要求主线程 在一种常用模式下执行运行循环。通过将标准用户默认值 NSRunWebKitOnAppKitThread的值设置为YES(以获取新行为 而不考虑链接)或NO(以获取旧行为而不考虑 链接),可以覆盖此行为 。

Source

+0

谢谢,你可能是正确的(所以我接受的答案)。我使用了TTTAttributedLabel方式,因为我也希望在这些attributesString中有可点击的“链接”。它的工作完美(在经历了一段艰难的时期,学习如何正确使用它)=非常快速+灵活且易于集成/管理+委托方法 – macbeb

+2

我想补充一点,苹果明确表示不要在后台线程上使用UIKit版本。我通过使用performSelectorOnMainThread解决了这个问题:object:waitUntilDone:它的作用就像一个魅力。 –

+0

@Jesse Naugher我意识到这有点旧,但是你如何结合你所评论的这个答案使用'performSelectorOnMainThread:object:waitUntilDone:'?遇到类似的问题并寻找修复程序。 –