Подтвердить что ты не робот

Сбой CoreText при запуске в нескольких потоках

У меня очень странная проблема с основным текстом, который иногда случайно и иногда воспроизводимо сбой моего приложения. Я использую его, чтобы выложить и сделать пару страниц. Я делаю это асинхронно в фоновом режиме, чтобы не блокировать пользовательский интерфейс.

В то время как это отлично работает в целом, оно иногда падает. Все эти сбои происходят в одной строке:

framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)myText);

Фактически, они также, похоже, исходят из аналогичной точки в рамках. Я знаю, что вам это не нравится, но вот глава журнала сбоев:

Thread 8 Crashed:
0   ???                             0x0764f446 typeinfo for FT::data_stream + 6
1   libCGFreetype.A.dylib           0x076048b8 FT::font::copy_table(unsigned int) const + 94
2   libCGFreetype.A.dylib           0x0760b085 (anonymous namespace)::copy_table(void*, unsigned int) + 53
3   CoreText                        0x00f9592e TBaseFont::CopyTable(unsigned int) const + 334
4   CoreText                        0x00f670f6 TAATMorphTable::TAATMorphTable(TLine&, long, unsigned int) + 110
5   CoreText                        0x00f6744c TAATMorphTableMorx::TAATMorphTableMorx(TLine&, long, TGlyphList<TDeletedGlyphIndex>&) + 54
6   CoreText                        0x00f53eb5 TShapingEngine::ShapeGlyphs(TLine&, TCharStream const&, CFRange&, TGlyphList<TDeletedGlyphIndex>*) + 215
7   CoreText                        0x00f579ce TTypesetter::FinishEncoding(TLine&, signed char, TGlyphList<TDeletedGlyphIndex>*) const + 260
8   CoreText                        0x00f6664b TTypesetterAttrString::Initialize(__CFAttributedString const*) + 543
9   CoreText                        0x00f6683e TTypesetterAttrString::TTypesetterAttrString(__CFAttributedString const*) + 158
10  CoreText                        0x00f6102e TFramesetterAttrString::TFramesetterAttrString(__CFAttributedString const*) + 86
11  CoreText                        0x00f6099e CTFramesetterCreateWithAttributedString + 78
...

Все сбои, которые я помню, были в функции FT::font::copy_table. Интересно, что чем сложнее требования шрифта, тем чаще случаются сбои. Китайский текст почти всегда крах - эти шрифты кажутся довольно сложными.

Обходной путь: Обходной путь, который я нашел, - это секвенировать вызовы на CTFramesetterCreateWithAttributedString в главной или отдельной. Проблема состоит в том, что этот единственный вызов составляет 79% от общей компоновки и времени рендеринга. Поэтому я хотел бы иметь его в нескольких потоках.

Вопрос: Любые профи вокруг этого могут помочь? Для меня это звучит как состояние гонки где-то глубоко. Я не нашел ничего, заявляя, что CoreText не может использоваться в потоковом режиме. И завтра я отправлю ошибку. Тем не менее, я мог бы просто что-то пропустить. Любые советы?

Спасибо, Макс

4b9b3361

Ответ 1

Я спросил некоторых инженеров во время WWDC, знают ли они эту проблему. Ответ: ДА. И на самом деле есть некоторые проблемы в подсистеме типов. Они могут сделать какое-то исправление, но на данный момент все, что осталось сделать, - это упорядочить весь макет текста.: (

Всем: ПОЖАЛУЙСТА, ОБНАРУЖИТЕ ФАЙЛЫ!

Ответ 2

Вот что documentation говорит:

Многоядерные соображения: все отдельные функции в основном тексте безопасный поток. Шрифтовые объекты (CTFont, CTFontDescriptor и связанные с ним объекты) могут использоваться одновременно несколькими операциями, рабочими очередями, или потоков. Однако макет объекты (CTTypesetter, CTFramesetter, CTRun, CTLine, CTFrame и связанные с ними объекты) должны использоваться в одном операции, рабочей очереди или потока.

Итак, я думаю, что нет сериализации вызовов CTFramesetterCreateWithAttributedString.

Ответ 3

CoreText занимает некоторое время, чтобы инициализировать таблицу поиска шрифтов, когда вы используете его в первый раз. Я предполагаю, что вы можете избавиться от своей проблемы, сначала инициировав загрузку этой таблицы, прежде чем переходить к нескольким потокам.

См. http://www.cocoanetics.com/2011/04/coretext-loading-performance/ для метода.

Ответ 4

Перед повторным открытием убедитесь, что вы сохранили набор фреймов. Это ДЕЙСТВИТЕЛЬНО не предназначено для использования асинхронно до 4.0!

CFRelease(framesetter);

Не могли бы вы также предоставить версию Xcode и iOS, с которыми вы работаете?

Ответ 5

исправить от меня:-) no crash больше

старый код

NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:aText];
[attributedString addAttribute:(id)kCTFontAttributeName value:(id)aFontRef range:NSMakeRange(0, [aText length])];

CTFramesetterRef framesetterRef = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attributedString);

новый код

CFMutableAttributedStringRef attributedStringRef = CFAttributedStringCreateMutable(nil, 0);
CFAttributedStringBeginEditing(attributedStringRef);
CFAttributedStringReplaceString(attributedStringRef, CFRangeMake(0, 0), (CFStringRef)aText);
CFAttributedStringSetAttribute(attributedStringRef, CFRangeMake(0, aText.length), kCTFontAttributeName, aFontRef);
CFAttributedStringEndEditing(attributedStringRef);

CTFramesetterRef framesetterRef = CTFramesetterCreateWithAttributedString(attributedStringRef);