NSMutableAttributedString initWithData: вызывать EXC_BAD_ACCESS при вращении

Я показываю различные типы содержимого в tableview и вычисляю высоту каждой ячейки с использованием разных пользовательских методов в heightForRowAtIndexPath.

Один из этих пользовательских методов подразумевает преобразование некоторого html в NSMutableAttributedString, а затем вычисление высоты этого NSMutableAttributedString.
Для преобразования html я использую новый метод initWithData:.

Все работает отлично, за исключением случаев, когда я поворачиваю экран = > У меня есть exc_bad_access каждый раз.

Используя инструменты/зомби, я смог найти ошибку, и на самом деле это initWithData:.

(Когда я удаляю этот метод и создаю "простой" NSMutableAttributedString с initWithString, я могу изменить ориентацию столько раз, сколько захочу, а не crash).

Любая идея, почему?

(Кстати, мой проект использует ARC)


Инструмент/Зомби скриншот: enter image description here


Пользовательский метод, вызываемый в heightForRowAtIndexPath:

< УтилитыForFrontEndUI 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 to NSMutableAttributedString:

< УтилитыForFrontEndUI 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;
}

Ответ 1

У меня такая же ситуация происходит в моем приложении.

[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 v10.4, NSAttributedString имеет используется WebKit для импорта (но не для экспорта) документов HTML. Поскольку загрузка документа WebKit не является потокобезопасной, это не было безопасный для использования на фоне потоков. Для приложений, связанных с OS X v10.5 и более поздних версий, если NSAttributedString импортирует HTML-документы на любой но основной поток, использование WebKit передается на главную thread через performSelectorOnMainThread: withObject: waitUntilDone:. Эта делает поток операций безопасным, но требует, чтобы основной поток выполнять цикл выполнения в одном из общих режимов. Это поведение можно переопределить, установив значение стандартного пользователя по умолчанию NSRunWebKitOnAppKitThread для YES (для получения нового поведения независимо от привязки) или НЕТ (для получения старого поведения независимо от связь).

Источник