AutoLayout: removeFromSuperview / removeConstraints throws exception and crashes hard

后端 未结 13 2201
谎友^
谎友^ 2020-11-27 11:05

We use auto layout constraints selectively, primarily to position labels in relation to editable field elements (UITextView, UITextField, typically). However, since impleme

相关标签:
13条回答
  • 2020-11-27 11:24

    For me the problem was that I was removing a constraint at a time that suited me, after calling dequeueReusableCellWithReuseIdentifier while setting properties of my UICollectionViewCell. The solution was to instead call:

        [_myUICollectionViewCell setNeedsUpdateConstraints];
    

    and override:

        -(void)updateConstraints 
    

    and do my messing there. Seems that you can't just remove constraints when you like.

    0 讨论(0)
  • 2020-11-27 11:24

    I got this problem with MZFormSheetController pod: https://github.com/m1entus/MZFormSheetController/issues/78

    This code crashes:

    [formSheetController.view addSubview:self.sharePanel];
    // ...
    [self.sharePanel removeFromSuperview]; // <-- CRASHES HERE
    

    My solution is very strange but it works:

    [self.sharePanel removeFromSuperview]; // <-- This line helps to avoid crash
    [formSheetController.view addSubview:self.sharePanel];
    // ...
    [self.sharePanel removeFromSuperview];
    

    And here is sharePanel property declaration:

    @property (weak, nonatomic) IBOutlet UIView *sharePanel;
    
    0 讨论(0)
  • 2020-11-27 11:25

    Deallocation problem — one possibility

    Your code that works with auto-layout may well run on the main thread but one of the blocks that's run in background and uses your view (perhaps indirectly), may hold a strong reference the view or one of its owner like view controller (that's the default behavior of Objective-C blocks). When such a block is run and deallocated on a background queue, strong references that it captures are released on that same queue and you may face a well known deallocation problem.

    1. In your view controller, make sure you are using weak reference to self in all blocks that do not need a strong reference (and may run in background). You can declare it like this: __weak typeof(self) weakSelf = self; before the block — and use weakSelf inside the block.

    2. Same goes for any local variables that hold references to your views — make sure their values are captured as weak refs.

    Another possibility

    In my work, I've encountered a similar issue on iOS 6 when hidden view participated in layout. Removing the view from hierarchy (-[UIView removeFromSuperview]) instead of setting hidden property to YES fixed the issue for me.

    0 讨论(0)
  • 2020-11-27 11:26

    According to Apple Documentation:

    When developing for iOS 8.0 or later, set the constraint’s active property to YES instead of calling the addConstraint: method directly. The active property automatically adds and removes the constraint from the correct view.

    In my case I had to modify the width constraint

    for var constraint in self.navigationBar.constraints {
                if constraint.identifier == "theProgressWidth" {
                    let sizeWidth = self.navigationBar.frame.size.width
                    constraint = NSLayoutConstraint(item: progress!, attribute: .Width, relatedBy: .Equal, toItem: self.navigationBar, attribute: .Width, multiplier: ((sizeWidth * (level / 100)) / sizeWidth), constant: 0)
                    constraint.active = true
                }
            }
    
    0 讨论(0)
  • 2020-11-27 11:27

    I am getting this crash when I call removeConstraints: with a nil argument.

    0 讨论(0)
  • 2020-11-27 11:28

    To make @smileyborg's awesome answer more actionable:

    This can happen if you have any constraints with multipliers that might suffer from floating point precision issues.

    To solve:

    1. Go over all your constraints that have multipliers (in layout code or by manually editing a storyboard/nib and searching for multiplier=).
    2. If multiplier isn't a "pretty" power of two float, turn it to the nearest one (you can use a floating point calculator)

    To easy way to do 2 is to enter the number you value you want and the calculator and then switch off lower precision bits in the mantissa until the value matches the rounded decimal value at bottom of the calculator.

    0 讨论(0)
提交回复
热议问题