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

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

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

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

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

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

Есть идеи почему?

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


Скриншот инструмента / зомби:


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

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 преобразование:

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 передается в основной поток через executeSelectorOnMainThread:withObject:waitUntilDone:. Это делает поток операций безопасным, но требует, чтобы основной поток выполнял цикл выполнения в одном из общих режимов. Это поведение можно переопределить, установив значение стандартного пользовательского значения по умолчанию NSRunWebKitOnAppKitThread либо в YES (для получения нового поведения независимо от связи), либо в NO (для получения старого поведения независимо от связи).

Источник

Другие вопросы по тегам