自定义SelfSizedTableView调用reloadData()崩溃问题求助
自定义SelfSizedTableView调用reloadData()崩溃的原因与解决办法
崩溃原因
从崩溃堆栈和自定义TableView代码来看,核心问题是布局操作的递归死循环:
- 在
reloadData()中调用layoutIfNeeded()会立即触发TableView的同步布局,包括cell创建、约束更新等操作。 - 布局过程中系统会读取
intrinsicContentSize,而该属性的getter里又调用了setNeedsLayout()和layoutIfNeeded(),再次触发布局流程。 - 这种循环会导致AutoLayout引擎(NSISEngine)反复尝试更新约束、插入布局变量,最终引发CoreAutoLayout内部的对象表操作异常,导致崩溃。
从堆栈可以看到,崩溃发生在TableView配置cell、更新可见cell的过程中,正是布局循环触发的关键节点。
解决办法
针对自定义TableView代码,需要修改两处核心逻辑打破布局循环:
修改1:重构reloadData方法
移除同步布局调用layoutIfNeeded(),只保留标记intrinsicContentSize需要更新的操作,让系统在合适时机异步处理布局:
open override func reloadData() { super.reloadData() invalidateIntrinsicContentSize() }
修改2:修正intrinsicContentSize的实现
intrinsicContentSize的getter应该是纯计算属性,不能触发布局操作(setNeedsLayout/layoutIfNeeded),正确实现只返回当前contentSize即可:
open override var intrinsicContentSize: CGSize { return CGSize( width: contentSize.width, height: contentSize.height ) }
可选优化:补充布局更新触发
如果需要确保contentSize变更时及时更新intrinsicContentSize,可以在layoutSubviews中补充标记:
open override func layoutSubviews() { super.layoutSubviews() invalidateIntrinsicContentSize() }
修改后,系统会在当前runloop结束后处理布局和intrinsicContentSize的更新,避免同步触发的循环问题。
原代码与崩溃堆栈
自定义SelfSizedTableView原代码
import UIKit open class SelfSizedTableView: UITableView { open override func reloadData() { super.reloadData() self.invalidateIntrinsicContentSize() self.layoutIfNeeded() } open override var intrinsicContentSize: CGSize { setNeedsLayout() layoutIfNeeded() return CGSize( width: contentSize.width, height: contentSize.height ) } }
崩溃堆栈信息
Crashed: com.apple.main-thread 0 CoreAutoLayout 0x17d38 object_table_insert_and_return_old_value_if_replaced + 96 1 CoreAutoLayout 0x8324 NSISObjectTableInsert + 72 2 CoreAutoLayout 0x80b0 -[NSISEngine startObservingChangesForVariable:] + 76 3 UIKitCore 0x373e2c _UILayoutItemSetUpVariableObservation + 144 4 UIKitCore 0x2aae18 _UILayoutItemCreateAndObserveVariableWithValueRestriction + 104 5 UIKitCore 0x518fc4 -[UIView nsli_boundsWidthVariable] + 48 6 UIKitCore 0x34b7e8 -[UIView(AdditionalLayoutSupport) nsli_lowerAttribute:intoExpression:withCoefficient:forConstraint:onBehalfOfLayoutGuide:] + 2860 7 UIKitCore 0x566e50 -[UIView(AdditionalLayoutSupport) nsli_lowerAttribute:intoExpression:withCoefficient:forConstraint:] + 316 8 CoreAutoLayout 0xbb50 -[NSLayoutConstraint _lowerIntoExpression:reportingConstantIsRounded:] + 76 9 CoreAutoLayout 0xdee8 -[NSLayoutConstraint _addToEngine:mutuallyExclusiveConstraints:] + 136 10 UIKitCore 0x1cd270 __57-[UIView(AdditionalLayoutSupport) _switchToLayoutEngine:]_block_invoke_2 + 368 11 CoreAutoLayout 0x7bac -[NSISEngine withBehaviors:performModifications:] + 80 12 UIKitCore 0x1badd0 __57-[UIView(AdditionalLayoutSupport) _switchToLayoutEngine:]_block_invoke + 528 13 UIKitCore 0x3980f4 -[UIView(AdditionalLayoutSupport) _switchToLayoutEngine:] + 188 14 UIKitCore 0x1cd1b8 __57-[UIView(AdditionalLayoutSupport) _switchToLayoutEngine:]_block_invoke_2 + 184 15 CoreAutoLayout 0x7bac -[NSISEngine withBehaviors:performModifications:] + 80 16 UIKitCore 0x1badd0 __57-[UIView(AdditionalLayoutSupport) _switchToLayoutEngine:]_block_invoke + 528 17 UIKitCore 0x3980f4 -[UIView(AdditionalLayoutSupport) _switchToLayoutEngine:] + 188 18 UIKitCore 0x1cd1b8 __57-[UIView(AdditionalLayoutSupport) _switchToLayoutEngine:]_block_invoke_2 + 184 19 CoreAutoLayout 0x7bac -[NSISEngine withBehaviors:performModifications:] + 80 20 UIKitCore 0x1badd0 __57-[UIView(AdditionalLayoutSupport) _switchToLayoutEngine:]_block_invoke + 528 21 UIKitCore 0x3980f4 -[UIView(AdditionalLayoutSupport) _switchToLayoutEngine:] + 188 22 UIKitCore 0x45ae68 -[UIView(AdditionalLayoutSupport) _initializeHostedLayoutEngine] + 208 23 UIKitCore 0x1da868 -[UIView _layoutEngine_windowDidChange] + 120 24 UIKitCore 0x29ebbc -[UIView(Internal) _didMoveFromWindow:toWindow:] + 276 25 UIKitCore 0x29ee48 -[UIView(Internal) _didMoveFromWindow:toWindow:] + 928 26 UIKitCore 0x1cb998 __45-[UIView(Hierarchy) _postMovedFromSuperview:]_block_invoke + 136 27 CoreAutoLayout 0x7bac -[NSISEngine withBehaviors:performModifications:] + 80 28 UIKitCore 0x2576e4 -[UIView(Hierarchy) _postMovedFromSuperview:] + 780 29 UIKitCore 0x179ca4 -[UIView(Internal) _addSubview:positioned:relativeTo:] + 2148 30 UIKitCore 0x38ec30 -[UITableView _addSubview:positioned:relativeTo:] + 104 31 UIKitCore 0x168d68 -[UIScrollView _addContentSubview:atBack:] + 376 32 UIKitCore 0x18d4e8 -[UITableView _addContentSubview:atBack:] + 248 33 UIKitCore 0x189e70 __53-[UITableView _configureCellForDisplay:forIndexPath:]_block_invoke + 1744 34 UIKitCore 0x1632d0 +[UIView(Animation) performWithoutAnimation:] + 96 35 UIKitCore 0x3f4664 -[UITableView _configureCellForDisplay:forIndexPath:] + 244 36 UIKitCore 0x27010c -[UITableView _createPreparedCellForGlobalRow:withIndexPath:willDisplay:] + 1916 37 UIKitCore 0x45a858 -[UITableView _updateVisibleCellsForRanges:createIfNecessary:] + 700 38 UIKitCore 0x293f04 -[UITableView _updateVisibleCellsNow:] + 1464 39 UIKitCore 0x16c484 -[UITableView layoutSubviews] + 436 40 UIKitCore 0x17c1d0 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 2556 41 QuartzCore 0x3d520 CA::Layer::layout_if_needed(CA::Transaction*) + 528 42 UIKitCore 0x1dd8b0 -[UIView(Hierarchy) layoutBelowIfNeeded] + 556 43 Drops 0x78e68 SelfSizedTableView.reloadData() + 15 (SelfSizedTableView.swift:15) 44 Drops 0x78eb8 @objc SelfSizedTableView.reloadData() + 4365668024 (<compiler-generated>:4365668024) 45 UIKitCore 0x16c300 -[UITableView layoutSubviews] + 48 46 UIKitCore 0x17c1d0 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 2556 47 QuartzCore 0x3d520 CA::Layer::layout_if_needed(CA::Transaction*) + 528 48 UIKitCore 0x1dd8b0 -[UIView(Hierarchy) layoutBelowIfNeeded] + 556 49 Drops 0x78f6c SelfSizedTableView.intrinsicContentSize.getter + 19 (SelfSizedTableView.swift:19) 50 Drops 0x78ef4 @objc SelfSizedTableView.intrinsicContentSize.getter + 4365668084 (<compiler-generated>:4365668084) 51 UIKitCore 0x19cae8 -[UIView _generateContentSizeConstraints] + 56 52 UIKitCore 0x24beac -[UIView _updateContentSizeConstraints] + 268 53 UIKitCore 0x2f6440 -[UIView(AdditionalLayoutSupport) _updateSystemConstraints] + 124 54 UIKitCore 0x35aaac -[UIView(AdditionalLayoutSupport) _sendUpdateConstraintsIfNecessaryForSecondPass:] + 480 55 UIKitCore 0x17f5a0 -[UIView(AdditionalLayoutSupport) _updateConstraintsIfNeededCollectingViews:forSecondPass:] + 996 56 UIKitCore 0x17f480 -[UIView(AdditionalLayoutSupport) _updateConstraintsIfNeededCollectingViews:forSecondPass:] + 708 57 UIKitCore 0x17f480 -[UIView(AdditionalLayoutSupport) _updateConstraintsIfNeededCollectingViews:forSecondPass:] + 708 58 CoreAutoLayout 0x7bac -[NSISEngine withBehaviors:performModifications:] + 80 59 UIKitCore 0x4f6720 -[UIView(AdditionalLayoutSupport) _recursiveUpdateConstraintsIfNeededCollectingViews:forSecondPass:] + 120 60 UIKitCore 0x17f480 -[UIView(AdditionalLayoutSupport) _updateConstraintsIfNeededCollectingViews:forSecondPass:] + 708 61 UIKitCore 0x1e494c __100-[UIView(AdditionalLayoutSupport) _updateConstraintsIfNeededWithViewForVariableChangeNotifications:]_block_invoke + 84 62 UIKitCore 0x25c954 -[UIView(AdditionalLayoutSupport) _updateConstraintsIfNeededWithViewForVariableChangeNotifications:] + 160 63 UIKitCore 0x314fd8 -[UIView(AdditionalLayoutSupport) _systemLayoutSizeFittingSize:withHorizontalFittingPriority:verticalFittingPriority:hasIntentionallyCollapsedHeight:] + 224 64 UIKitCore 0x272668 -[UITableViewCell systemLayoutSizeFittingSize:withHorizontalFittingPriority:verticalFittingPriority:] + 656 65 UIKitCore 0x331148 -[UITableView _heightForCell:atIndexPath:] + 400 66 UIKitCore 0x18a120 __53-[UITableView _configureCellForDisplay:forIndexPath:]_block_invoke + 2432 67 UIKitCore 0x1632d0 +[UIView(Animation) performWithoutAnimation:] + 96 68 UIKitCore 0x3f4664 -[UITableView _configureCellForDisplay:forIndexPath:] + 244 69 UIKitCore 0x27010c -[UITableView _createPreparedCellForGlobalRow:withIndexPath:willDisplay:] + 1916 70 UIKitCore 0x44a10c -[UITableView _createPreparedCellForRowAtIndexPath:willDisplay:] + 88 71 UIKitCore 0x534d90 -[UITableView _heightForRowAtIndexPath:] + 152 72 UIKitCore 0x1cab54 -[UISectionRowData heightForRow:inSection:canGuess:] + 208 73 UIKitCore 0x16ee8c -[UITableViewRowData heightForRow:inSection:canGuess:adjustForReorderedRow:] + 252 74 UIKitCore 0x237c54 -[UITableViewRowData rectForRow:inSection:heightCanBeGuessed:] + 332 75 UIKitCore 0x16c890 -[UITableViewRowData rectForGlobalRow:heightCanBeGuessed:] + 108 76 UIKitCore 0x277eb0 -[UITableView _prefetchCellAtGlobalRow:aboveVisibleRange:] + 264 77 UIKitCore 0x1c52f4 __48-[UITableView _configureCellPrefetchingHandlers]_block_invoke + 56 78 UIKitCore 0x170804 -[_UITableViewPrefetchContext updateVisibleIndexRange:withContentOffset:] + 2392 79 UIKitCore 0x42db08 -[UITableView _updateCycleIdleUntil:] + 188 80 UIKitCore 0x17e2b8 ___UIUpdateCycleNotifyIdle_block_invoke + 704 81 libdispatch.dylib 0x63094 _dispatch_call_block_and_release + 24 82 libdispatch.dylib 0x64094 _dispatch_client_callout + 16 83 libdispatch.dylib 0x45858 _dispatch_main_queue_drain + 888 84 libdispatch.dylib 0x454d0 _dispatch_main_queue_callback_4CF$VARIANT$armv81 + 36 85 CoreFoundation 0x4e0d4 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 12 86 CoreFoundation 0xb5f8 __CFRunLoopRun + 2544 87 CoreFoundation 0x1e250 CFRunLoopRunSpecific + 572 88 GraphicsServices 0x1988 GSEventRunModal + 160 89 UIKitCore 0x4e5a94 -[UIApplication _run] + 1080 90 UIKitCore 0x27efd4 UIApplicationMain + 336 91 libswiftUIKit.dylib 0x27ee4 UIApplicationMain(_:_:_:_:) + 100 92 Drops 0x1249a0 static UIApplicationDelegate.main() + 4366371232 (<compiler-generated>:4366371232) 93 Drops 0x124928 static AppDelegate.$main() + 25 (<compiler-generated>:25) 94 Drops 0x1263e8 main + 26 (AppDelegate.swift:26) 95 ??? 0x1036b44d0 (Missing)
内容的提问来源于stack exchange,提问作者Mohamed Mostafa Fawzi
相关产品推荐
相关产品推荐

