In iOS 8 (or possibly even in iOS 7/7.1) NSAttributedString
on iOS added the ability to render text tables. This API is public on OS X but not on iOS. However, it is possible to create an attributed string containing a text table on iOS by passing HTML containing a table to -[NSAttributedString initWithData:options:documentAttributes:error:]
.
The attributed string is created correctly, but when I attempt to render the string using a UITextView
, this exception gets thrown:
<NSATSTypesetter: 0x7f8900faec90>: Exception *** -[NSConcreteTextStorage attribute:atIndex:effectiveRange:]: Range or index out of bounds raised during typesetting layout manager <NSLayoutManager: 0x7f8902e13440>
1 containers, text backing has 1884 characters
Currently holding 1884 glyphs.
Glyph tree contents: 1884 characters, 1884 glyphs, 1 nodes, 64 node bytes, 7680 storage bytes, 7744 total bytes, 4.11 bytes per character, 4.11 bytes per glyph
Layout tree contents: 1884 characters, 1884 glyphs, 417 laid glyphs, 3 laid line fragments, 3 nodes, 192 node bytes, 1568 storage bytes, 1760 total bytes, 0.93 bytes per character, 0.93 bytes per glyph, 139.00 laid glyphs per laid line fragment, 586.67 bytes per laid line fragment, glyph range {417 4}. Ignoring...
This is the backtrace:
thread #1: tid = 0x14334, 0x000000010ec0bb8a libobjc.A.dylib`objc_exception_throw, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
frame #0: 0x000000010ec0bb8a libobjc.A.dylib`objc_exception_throw
frame #1: 0x000000010ef72e6d CoreFoundation`+[NSException raise:format:] + 205
frame #2: 0x0000000112ebe9f6 UIFoundation`-[NSConcreteTextStorage attribute:atIndex:effectiveRange:] + 131
frame #3: 0x0000000112e8a51b UIFoundation`-[NSAttributedString(NSAttributedStringUIFoundationAdditions) rangeOfTextTable:atIndex:] + 65
frame #4: 0x0000000112ec0e1b UIFoundation`-[NSTextBlockLayoutHelper initWithTextTable:charIndex:text:layoutManager:containerWidth:collapseBorders:] + 376
frame #5: 0x0000000112ec585f UIFoundation`-[NSTextTable rectForBlock:layoutAtPoint:inRect:textContainer:characterRange:] + 355
frame #6: 0x0000000112ec3c3b UIFoundation`-[NSTextTableBlock rectForLayoutAtPoint:inRect:textContainer:characterRange:] + 116
frame #7: 0x0000000112ecdb3b UIFoundation`-[NSTypesetter getLineFragmentRect:usedRect:remainingRect:forStartingGlyphAtIndex:proposedRect:lineSpacing:paragraphSpacingBefore:paragraphSpacingAfter:] + 2204
frame #8: 0x0000000112e702c3 UIFoundation`-[NSATSTypesetter _layoutLineFragmentStartingWithGlyphAtIndex:characterIndex:atPoint:renderingContext:] + 1716
frame #9: 0x0000000112e71dfc UIFoundation`-[NSATSTypesetter layoutParagraphAtPoint:] + 156
frame #10: 0x0000000112ecb643 UIFoundation`-[NSTypesetter _layoutGlyphsInLayoutManager:startingAtGlyphIndex:maxNumberOfLineFragments:maxCharacterIndex:nextGlyphIndex:nextCharacterIndex:] + 3391
frame #11: 0x0000000112ecccf9 UIFoundation`-[NSTypesetter layoutCharactersInRange:forLayoutManager:maximumNumberOfLineFragments:] + 246
frame #12: 0x0000000112e72761 UIFoundation`-[NSATSTypesetter layoutCharactersInRange:forLayoutManager:maximumNumberOfLineFragments:] + 388
frame #13: 0x0000000112e5cb4a UIFoundation`-[NSLayoutManager(NSPrivate) _fillLayoutHoleForCharacterRange:desiredNumberOfLines:isSoft:] + 1258
frame #14: 0x0000000112e5e5b7 UIFoundation`-[NSLayoutManager(NSPrivate) _fillLayoutHoleAtIndex:desiredNumberOfLines:] + 201
frame #15: 0x0000000112e5ec3f UIFoundation`-[NSLayoutManager(NSPrivate) _markSelfAsDirtyForBackgroundLayout:] + 344
frame #16: 0x0000000112e68e3d UIFoundation`-[NSLayoutManager(NSPrivate) _invalidateLayoutForExtendedCharacterRange:isSoft:invalidateUsage:] + 2143
frame #17: 0x0000000112e9484b UIFoundation`-[NSLayoutManager textContainerChangedGeometry:] + 315
frame #18: 0x0000000112eb906d UIFoundation`-[NSTextContainer setSize:] + 200
frame #19: 0x000000010fcb5a0e UIKit`__47-[UITextView _performLayoutCalculation:inSize:]_block_invoke + 229
frame #20: 0x0000000112e9e718 UIFoundation`-[NSLayoutManager(TextLocking) coordinateAccess:] + 55
frame #21: 0x000000010fcb591a UIKit`-[UITextView _performLayoutCalculation:inSize:] + 223
frame #22: 0x000000010fcb5d04 UIKit`-[UITextView _intrinsicSizeWithinSize:] + 411
frame #23: 0x000000010fcb5f17 UIKit`-[UITextView intrinsicContentSize] + 130
frame #24: 0x000000010fc21ea4 UIKit`-[UIView(UIConstraintBasedLayout) _generateContentSizeConstraints] + 33
frame #25: 0x000000010fc21c64 UIKit`-[UIView(UIConstraintBasedLayout) _updateContentSizeConstraints] + 422
frame #26: 0x000000010fc290d6 UIKit`-[UIView(AdditionalLayoutSupport) updateConstraints] + 163
frame #27: 0x000000010fcb62e7 UIKit`-[UITextView updateConstraints] + 271
frame #28: 0x000000010fc286fa UIKit`-[UIView(AdditionalLayoutSupport) _internalUpdateConstraintsIfNeededAccumulatingViewsNeedingSecondPassAndViewsNeedingBaselineUpdate:] + 248
frame #29: 0x000000010fc288f2 UIKit`-[UIView(AdditionalLayoutSupport) _updateConstraintsIfNeededAccumulatingViewsNeedingSecondPassAndViewsNeedingBaselineUpdate:] + 124
frame #30: 0x000000010ee7b194 CoreFoundation`CFArrayApplyFunction + 68
frame #31: 0x000000010fc2869b UIKit`-[UIView(AdditionalLayoutSupport) _internalUpdateConstraintsIfNeededAccumulatingViewsNeedingSecondPassAndViewsNeedingBaselineUpdate:] + 153
frame #32: 0x000000010fc288f2 UIKit`-[UIView(AdditionalLayoutSupport) _updateConstraintsIfNeededAccumulatingViewsNeedingSecondPassAndViewsNeedingBaselineUpdate:] + 124
frame #33: 0x000000010ee7b194 CoreFoundation`CFArrayApplyFunction + 68
frame #34: 0x000000010fc2869b UIKit`-[UIView(AdditionalLayoutSupport) _internalUpdateConstraintsIfNeededAccumulatingViewsNeedingSecondPassAndViewsNeedingBaselineUpdate:] + 153
frame #35: 0x000000010fc288f2 UIKit`-[UIView(AdditionalLayoutSupport) _updateConstraintsIfNeededAccumulatingViewsNeedingSecondPassAndViewsNeedingBaselineUpdate:] + 124
frame #36: 0x000000010fc28dbe UIKit`__60-[UIView(AdditionalLayoutSupport) updateConstraintsIfNeeded]_block_invoke + 96
frame #37: 0x000000010fc28a86 UIKit`-[UIView(AdditionalLayoutSupport) updateConstraintsIfNeeded] + 231
frame #38: 0x000000010fa1e8b8 UIKit`-[UITableViewCellContentView updateConstraintsIfNeeded] + 95
frame #39: 0x000000010fc253a9 UIKit`-[UIView(AdditionalLayoutSupport) _systemLayoutSizeFittingSize:withHorizontalFittingPriority:verticalFittingPriority:hasIntentionallyCollapsedHeight:] + 298
frame #40: 0x000000010f82790d UIKit`-[UITableViewCell systemLayoutSizeFittingSize:withHorizontalFittingPriority:verticalFittingPriority:] + 316
frame #41: 0x000000010f69fd65 UIKit`-[UITableView _heightForCell:atIndexPath:] + 363
frame #42: 0x000000010f6926e7 UIKit`__53-[UITableView _configureCellForDisplay:forIndexPath:]_block_invoke + 1917
frame #43: 0x000000010f6135ce UIKit`+[UIView(Animation) performWithoutAnimation:] + 65
frame #44: 0x000000010f691f5b UIKit`-[UITableView _configureCellForDisplay:forIndexPath:] + 312
frame #45: 0x000000010f6994cc UIKit`-[UITableView _createPreparedCellForGlobalRow:withIndexPath:willDisplay:] + 533
frame #46: 0x000000010f678fb1 UIKit`-[UITableView _updateVisibleCellsNow:isRecursive:] + 2846
frame #47: 0x000000010f68ee3c UIKit`-[UITableView layoutSubviews] + 213
frame #48: 0x000000010f61b973 UIKit`-[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 521
frame #49: 0x000000010e11dde8 QuartzCore`-[CALayer layoutSublayers] + 150
frame #50: 0x000000010e112a0e QuartzCore`CA::Layer::layout_if_needed(CA::Transaction*) + 380
frame #51: 0x000000010e11287e QuartzCore`CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 24
frame #52: 0x000000010e08063e QuartzCore`CA::Context::commit_transaction(CA::Transaction*) + 242
frame #53: 0x000000010e08174a QuartzCore`CA::Transaction::commit() + 390
frame #54: 0x000000010e081db5 QuartzCore`CA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*) + 89
frame #55: 0x000000010eea7dc7 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23
frame #56: 0x000000010eea7d20 CoreFoundation`__CFRunLoopDoObservers + 368
frame #57: 0x000000010ee9db53 CoreFoundation`__CFRunLoopRun + 1123
frame #58: 0x000000010ee9d486 CoreFoundation`CFRunLoopRunSpecific + 470
frame #59: 0x00000001139eb9f0 GraphicsServices`GSEventRunModal + 161
frame #60: 0x000000010f5a2420 UIKit`UIApplicationMain + 1282
frame #61: 0x000000010d8cb33e MyApp`top_level_code + 78 at AppDelegate.swift:12
frame #62: 0x000000010d8cb37a MyApp`main + 42 at AppDelegate.swift:0
frame #63: 0x0000000111cbd145 libdyld.dylib`start + 1
I assumed this was a bug on Apple's part and tried to create a minimal project to reproduce the issue, but was unable to do so. Rendering the exact same attributed string in my test project worked fine, but still does not work in my app, which leads me to believe that maybe I'm doing something wrong. Rendering an attributed string without a table works fine, it's a problem that is specific to rendering tables. Has anyone else run into a similar problem?
来源:https://stackoverflow.com/questions/27759741/uitextview-crash-in-ios-8-with-attributed-string-containing-a-table