2013-12-22 7 views
13

tableviewにさまざまなタイプのコンテンツを表示し、異なるカスタムメソッドを使用して各セルの高さを計算します(heightForRowAtIndexPath)。NSMutableAttributedString initWithData:回転時にEXC_BAD_ACCESSを発生させる

これらのカスタムメソッドの1つは、NSMutableAttributedStringで一部のhtmlを変換し、次にこの高さを計算することを意味します。NSMutableAttributedString
html変換では、新しいinitWithData:メソッドを使用します。

私は画面を回転させる以外はすべて完璧に動作します=>私は毎回exc_bad_accessを持っています。

Instruments/Zombiesを使用して、私はエラーを見つけることができました。実際はinitWithData:です。

(この方法を削除してinitWithStringで「シンプル」NSMutableAttributedStringを作成すると、何度でも向きを変更できます。いいえ、crashはもうありません)。

理由は何ですか?

(ちなみに、私のプロジェクトは、ARCを使用)


インストゥルメント/ゾンビのスクリーンショット:heightForRowAtIndexPathで呼び出さ enter image description here


カスタム方法:

< 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); 
} 

NSMutableAttributedString変換するHTMLのためinitWithDataを使用したカスタム方法:

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

私はこれ以上のEXC_BAD_ACCESS簡単なinitWithStringでinitWithDataを交換する場合

+(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文書をメインスレッドにインポートする場合、WebKitの使用はperformSelectorOnMainThread:withObject:waitUntilDone:を介してメインの スレッドに転送されます。この は、スレッドを安全にしますが、メインスレッド が共通モードの1つで実行ループを実行する必要があります。この動作 は、標準ユーザーのデフォルト値 NSRunWebKitOnAppKitThreadの値をYES(リンケージに関係なく新しい動作 を取得する)またはNO( のリンケージに関係なく古い動作を取得する)に設定することでオーバーライドできます。

Source

+0

おかげで、あなたは(私は答えを受け入れた)、おそらく正しいです。私は、これらのattributedStringの中にクリック可能な "リンク"を持っていたかったので、TTTAttributedLabelの方法で行った。非常に速く、柔軟性があり、+デリゲートメソッドを統合/管理するのが難しいです。 – macbeb

+2

私はAppleがバックグラウンドスレッドでUIKitバージョンを使わないと明言しています。 performSelectorOnMainThread:object:waitUntilDone:を使用してこれを修正しました。これは魅力的です。 –

+0

@Jesse Naugher私はこれはやや古いことを認識していますが、あなたがコメントしたこの答えと一緒に 'performSelectorOnMainThread:object:waitUntilDone:'をどう使ったのですか?同様の問題にぶつかり、修正を探しています。 –

関連する問題