Swift: Crash on removeFromSuperview()
Asked Answered
G

4

7

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

Generative answered 9/12, 2016 at 6:24 Comment(6)
brother check your constrain when you remove from superview its constrain problem with your subview so its crashReyna
can you just replace everything you have there? removing subviews in cells is really slow, just set that content to nil and make it again if you needImprinting
why are u removing the subviews???Paramount
If you need just update cells you need to update views with new content. You don't need to remove views and add them again. I think, the crash happen because you remove cell subviews while it is not on screen, but in reusing pool.Triggerfish
Is this now solved?Afternoons
Hmm, I wouldn't say it's solved. Agreed, that a better approach would be to set the content to nil, but I'm looking for some insight as to why these calls are crashing, particularly this one stackView.subviews.first?.removeFromSuperview()Generative
D
1

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() })
    }
}
Downfall answered 6/10, 2017 at 7:46 Comment(3)
Is this working? For me its crashing while removing all subview from cell.Retrench
Yes I have similar code and now it is crashing but I've used it in other place and it work. So it depends or something have changed over last years. Now in iOS 13 it seems that I can remove using just removeArrangedSubviews() and do not need to deactivate constraints and remove from superviewPteridophyte
I posted my answer it seems to work just placed all this code in one loopPteridophyte
I
1

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.

Irrupt answered 19/4, 2019 at 13:13 Comment(0)
P
0
 for subview in stackView.subviews {
        stackView.removeArrangedSubview(subview)
        NSLayoutConstraint.deactivate(subview.constraints)
        subview.removeFromSuperview()
    }
 print("subviews: \(stackView.subviews)")
 // subviews: []
Peal answered 19/4, 2019 at 11:6 Comment(0)
S
0

I am doing it this way and it seems to work better then having 3 independent loops

extension UIStackView {
    func removeAllArrangedSubviews() {
            arrangedSubviews.forEach {
                self.removeArrangedSubview($0)
                NSLayoutConstraint.deactivate($0.constraints)
                $0.removeFromSuperview()
            }
        }
}
Sillsby answered 2/4, 2020 at 9:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.