CoreText在multithreading中运行时崩溃

我有一个非常奇怪的核心文本的问题,有时随机,有时可重复崩溃我的应用程序。 我用它来布置和渲染几页。 我在后台asynchronous执行此操作,以阻止用户界面。

虽然这一般正常工作,它有时会崩溃。 所有这些崩溃发生在同一行:

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可能不会被使用线程。 明天我会提交一个bug。 不过,我也可能错过了一些东西。 有什么build议?

谢谢,马克斯

在WWDC期间,我问过一些工程师是否知道这个问题。 答案是肯定的。 事实上在types子系统中存在一些问题。 他们可能有一天会做一些修改,但现在只剩下所有文本布局的序列化了。 🙁

每个人: 请文件错误!

这是什么文件说:

多核考虑因素:核心文本中的所有单个函数都是线程安全的。 字体对象(CTFont,CTFontDescriptor和相关的对象)可以被多个操作,工作队列或线程同时使用。 但是,布局对象(CTTypesetter,CTFramesetter,CTRun,CTLine,CTFrame和相关对象)应该用在单个操作,工作队列或线程中。

所以我想没有办法绕开序列化调用CTFramesetterCreateWithAttributedString

当您第一次使用CoreText时,CoreText需要一段时间来初始化字体查找表。 我想你可能能够摆脱你的问题,在进入多个线程之前首先触发加载这个表。

有关方法,请参阅http://www.cocoanetics.com/2011/04/coretext-loading-performance/

请确保在重新打开之前保留了framesetter。 这实际上并不意味着在4.0之前使用asynchronous!

 CFRelease(framesetter); 

你能不能也提供你正在使用的Xcode和iOS版本?

修理从我:-)没有崩溃了

旧代码

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