Problem: App crashes when I attempt to remove subview.
Context: I have a UICollectionViewCell that gets updated with a model object. I've tried putting these methods in prepareForReuse
and/or the update(model: viewModel)
method.
Notes: The line That view's superview: NO SUPERVIEW
sticks out. I went as far as adding the subview back into before calling removeFromSuperView()
to ensure there was some in a superView and it would still crash.
I later re-add newly generated instances of the class timelineView
once all the old ones are cleared out.
It only crashes after scrolling through about ~50-150 cells
Update: Thank you for your feedback in the comments. I'm not removing all the views from the cell. Just one stackview with a variable number of components. But your right about removing subviews vs nil'ing out. I'm more curious how things like stackView.subviews.first?.removeFromSuperview()
can fail, since it seems like a relatively safe call (or I'm dead wrong about this).
First Try
for subview in stackView.subviews {
subview.removeFromSuperview() // Crash
}
Second Try
let subviews = stackView.subviews
for subview in subviews {
if stackView != nil && subview.superview != nil && subview.responds(to: #selector(removeFromSuperview)) && stackView.superview != nil {
stackView.subviews.first?.removeFromSuperview() // Crash
}
}
Third Try
let subviews = stackView.subviews
for subview in subviews {
if stackView != nil && subview.superview != nil && subview.responds(to:#selector(removeFromSuperview)) && stackView.superview != nil {
if var firstSubview = stackView.subviews.first {
for constraint in firstSubview.constraints {
constraint.isActive = false
}
stackView.removeArrangedSubview(firstSubview)
firstSubview.removeFromSuperview() // Crash
}
}
}
Exception:
2016-12-09 00:56:26.792168 appName[59081:4139912] [LayoutConstraints] View hierarchy unprepared for constraint.
Constraint: <NSLayoutConstraint:0x618000490cc0 'UISV-canvas-connection' UIStackView:0x7fe25cd25dd0.bottom == appName.timeLineView:0x7fe25e007890.bottom (active)>
Container hierarchy:
<UIStackView: 0x7fe25cd25dd0; frame = (0 0; 718 40); opaque = NO; autoresize = RM+BM; layer = <CATransformLayer: 0x6080002295a0>>
View not found in container hierarchy: <appName.timeLineView: 0x7fe25e007890; frame = (0 0; 718 40); autoresize = W+H; layer = <CALayer: 0x610000835c40>>
That view's superview: NO SUPERVIEW
2016-12-09 00:58:38.655 appName[59081:4139912] *** Terminating app due to uncaught exception 'NSGenericException', reason: 'Unable to install constraint on view. Does the constraint reference something from outside the subtree of the view? That's illegal. constraint:<NSLayoutConstraint:0x618000490cc0 'UISV-canvas-connection' UIStackView:0x7fe25cd25dd0.bottom == appName.timeLineView:0x7fe25e007890.bottom (active)> view:<UIStackView: 0x7fe25cd25dd0; frame = (0 0; 718 40); opaque = NO; autoresize = RM+BM; layer = <CATransformLayer: 0x6080002295a0>>'
*** First throw call stack:
(
0 CoreFoundation 0x000000010df0434b __exceptionPreprocess + 171
1 libobjc.A.dylib 0x000000011215121e objc_exception_throw + 48
2 CoreFoundation 0x000000010df6d265 +[NSException raise:format:] + 197
3 Foundation 0x000000010f097865 -[NSLayoutConstraint _addToEngine:integralizationAdjustment:mutuallyExclusiveConstraints:] + 200
4 Foundation 0x000000010f27c6ed __36-[NSISEngine rebuildFromConstraints]_block_invoke + 208
5 Foundation 0x000000010f09dbd0 -[NSISEngine withBehaviors:performModifications:] + 155
6 Foundation 0x000000010f27c610 -[NSISEngine rebuildFromConstraints] + 488
7 Foundation 0x000000010f0a3e1a -[NSISEngine optimize] + 121
8 Foundation 0x000000010f27c883 -[NSISEngine _optimizeIfNotDisabled] + 57
9 Foundation 0x000000010f0a4ec3 -[NSISEngine removeConstraintWithMarker:] + 799
10 Foundation 0x000000010f09bca8 -[NSLayoutConstraint _removeFromEngine:] + 229
11 UIKit 0x00000001112314a0 -[UIView(UIConstraintBasedLayout) _layoutEngine_willRemoveLayoutConstraint:] + 105
12 UIKit 0x0000000111231bb1 -[UIView(UIConstraintBasedLayout) nsli_removeConstraint:] + 93
13 UIKit 0x0000000111243cef _UIViewRemoveConstraintsMadeDanglyByChangingSuperview + 1016
14 UIKit 0x000000011091965a __45-[UIView(Hierarchy) _postMovedFromSuperview:]_block_invoke + 61
15 UIKit 0x00000001109195a2 -[UIView(Hierarchy) _postMovedFromSuperview:] + 857
16 UIKit 0x000000011091721c __UIViewWasRemovedFromSuperview + 172
17 UIKit 0x0000000110916d13 -[UIView(Hierarchy) removeFromSuperview] + 564
18 appName 0x0000000109aad884 _TFC10appName22TestCollectionViewCell15prepareForReusefT_T_ + 3380
19 appName 0x0000000109aada42 _TToFC10appName22TestCollectionViewCell15prepareForReusefT_T_ + 34
20 UIKit 0x00000001111bee14 -[UICollectionView _dequeueReusableViewOfKind:withIdentifier:forIndexPath:viewCategory:] + 561
21 UIKit 0x00000001111bf834 -[UICollectionView dequeueReusableCellWithReuseIdentifier:forIndexPath:] + 169
22 appName 0x0000000109a83623 _TFC10appName30FlightsViewController14collectionViewfTCSo16UICollectionView13cellForItemAtV10Foundation9IndexPath_CSo20UICollectionViewCell + 339
23 appName 0x0000000109a83ca7 _TToFC10appName30FlightsViewController14collectionViewfTCSo16UICollectionView13cellForItemAtV10Foundation9IndexPath_CSo20UICollectionViewCell + 87
24 UIKit 0x00000001111aa980 -[UICollectionView _createPreparedCellForItemAtIndexPath:withLayoutAttributes:applyAttributes:isFocused:notify:] + 467
25 UIKit 0x00000001111aa7a7 -[UICollectionView _createPreparedCellForItemAtIndexPath:withLayoutAttributes:applyAttributes:] + 35
26 UIKit 0x00000001111afc7f -[UICollectionView _updateVisibleCellsNow:] + 4803
27 UIKit 0x00000001111b5913 -[UICollectionView layoutSubviews] + 313
28 UIKit 0x000000011092cf50 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 1237
29 QuartzCore 0x00000001102c9cc4 -[CALayer layoutSublayers] + 146
30 QuartzCore 0x00000001102bd788 _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 366
31 QuartzCore 0x00000001102bd606 _ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE + 24
32 QuartzCore 0x000000011024b680 _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 280
33 QuartzCore 0x0000000110278767 _ZN2CA11Transaction6commitEv + 475
34 QuartzCore 0x00000001101d3b97 _ZN2CA7Display11DisplayLink14dispatch_itemsEyyy + 611
35 CoreFoundation 0x000000010de96964 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 20
36 CoreFoundation 0x000000010de965f3 __CFRunLoopDoTimer + 1075
37 CoreFoundation 0x000000010de9617a __CFRunLoopDoTimers + 250
38 CoreFoundation 0x000000010de8df01 __CFRunLoopRun + 2065
39 CoreFoundation 0x000000010de8d494 CFRunLoopRunSpecific + 420
40 GraphicsServices 0x00000001144e9a6f GSEventRunModal + 161
41 UIKit 0x0000000110868964 UIApplicationMain + 159
42 appName 0x0000000109a2ba9f main + 111
43 libdyld.dylib 0x00000001133b468d start + 1
)
Thank you
Had a similar issue, and I think I've solved it just now by being very careful when removing items from the stackview - here's an extension that sums it up:
extension UIStackView {
func safelyRemoveArrangedSubviews() {
// Remove all the arranged subviews and save them to an array
let removedSubviews = arrangedSubviews.reduce([]) { (sum, next) -> [UIView] in
self.removeArrangedSubview(next)
return sum + [next]
}
// Deactive all constraints at once
NSLayoutConstraint.deactivate(removedSubviews.flatMap({ $0.constraints }))
// Remove the views from self
removedSubviews.forEach({ $0.removeFromSuperview() })
}
}
The problem is linked to your view LayoutConstraints
.
It seems one constraint named UISV-canvas-connection
is based on the view you are removing:
2016-12-09 00:56:26.792168 appName[59081:4139912] [LayoutConstraints] View hierarchy unprepared for constraint.
Constraint: <NSLayoutConstraint:0x618000490cc0 'UISV-canvas-connection' UIStackView:0x7fe25cd25dd0.bottom == appName.timeLineView:0x7fe25e007890.bottom (active)>
Container hierarchy:
<UIStackView: 0x7fe25cd25dd0; frame = (0 0; 718 40); opaque = NO; autoresize = RM+BM; layer = <CATransformLayer: 0x6080002295a0>>
View not found in container hierarchy: <appName.timeLineView: 0x7fe25e007890; frame = (0 0; 718 40); autoresize = W+H; layer = <CALayer: 0x610000835c40>>
That view's superview: NO SUPERVIEW
This constraint is base on a UIStackView that is no more in the view hierarchy (thus the message: That view's superview: NO SUPERVIEW
).
So the constraint can't be evaluated based on this view after it was removed from superview.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With