UIKitCore layoutGuides deadlock

195 Views Asked by At

I am creating a popup menu. It has a UIPresentationController that calculates frameOfPresentedViewInContainerView based on presented view controller's view size before showing it.

  • Presented view controllers consist of the fixed height outer (navigation) view controller embedding some dynamic height inner (content) view controller;
  • Inner view controllers, under the hood, have UIStackView wrapped in a UIScrollView;
  • Before calculating size of inner view controller I am calling layoutIfNeeded() on it.

The problem occurred only on devices with the notch (I blame safeAreaLayout) and only with a UIStackView-based inner view controllers. When layoutIfNeeded() called on presented controller (e.x. when display orientation change, content size change, or presented second time) UIKitCore goes into an infinite loop calling -[UIView layoutGuides]. It doesn't crash the app, but use 100% of the main thread and freezes the UI(sometimes whole phone to the point you need make a hard reset), consuming about 10Mb of memory every second.

I was able to fix it by adding 1 extra point to a calculated height of the frameOfPresentedViewInContainerView. This sounds like an awful fix, so I am trying to better understand the problem.

I would be glad if someone with a deep understanding of UIKit could point me to a better strategy on how to debug/investigate the issue.


UPDATE

Seems like UIScrollView having hard time positioning content due to a safeArea. UIKitCore keeps repeating those 5 lines:

- [UIScrollView _layoutGuideOfType:createIfNecessary:]
- [NSISEngine(_UILayoutEngineStatistics)_UIKitPerformPendingChangeNotifications]
- [UIView layoutGuides]
- [_UIScrollViewScrollIndicator _layoutFillViewAnimated:]
- [UIView(AdditionalLayoutSupport) nsli_lowerAttribute:intoExpression:withCoefficient:forConstraint:onBehalfOfLayoutGuide:]

I also have

runtime: Layout Issues: Scrollable content size is ambiguous for UIScrollView.
1

There are 1 best solutions below

1
Vladimir On

I was able to fix my issue by specifically attaching UIScrollView to the bottom of safeAreaLayoutGuide.

var bottomConstraint = formView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
if #available(iOS 11.0, *) {
    bottomConstraint = formView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor)
}