AutoLayout: removeFromSuperview / removeConstraints throws an exception and crashes badly

We use the limitations of the automatic layout selectively, primarily to position labels relative to the editable field elements (usually UITextView, UITextField). However, since the introduction of the automatic layout for these fields, we have seen an unpleasant exception and failure with every upload of views, release, etc. Exceptions occur when it tries to remove constraints from a view before unloading it.

Our vision / controller hierarchy is as follows:

UITableViewController (plain style, but with cell appearance to mimic grouped style) --> UITableViewCell ----> UIViewController (container for editable form) ------> UICollectionViewController (editable form) --------> UICollectionViewCell -----------> UIViewController (editable field) --------------> UILabel (field label) **HAS CONSTRAINTS** --------------> UITextView / UITextField (field value) **HAS CONSTRAINTS** 

Many times, when the cells of the top-level table are freed / replaced / reloaded, we see a huge exception, and then crash when trying to free / unload the view hierarchy inside.

I tried to mitigate the crash by catching an exception (without help), and also resolutely removing all restrictions on the affected view and all subitems before releasing / unloading (in viewWillDisappear: , and this does not seem to help. I even tried to remove these restrictions one by one to see if there is, in particular, what causes the problems, but they all explode when we call removeConstraint: or removeConstraints: on the container, preparing to disappear.

I am puzzled! Here comes a fragment of our exception - about 3,000 lines, so if you need more, just ask.

 Exception while deallocating view: { Rows: 0x18911270.posErrorMarker == 4 + 1*0x18911270.negError + 1*0x189112f0.marker + -1*0x189113f0.negError + 1*0x189113f0.posErrorMarker + 1*0x18911a60.marker + -0.5*0x1892dae0.negError + 0.5*0x1892dae0.posErrorMarker + 1*0x18951520.negError + -1*0x18951520.posErrorMarker + -0.5*0x18958090.negError + 0.5*0x18958090.posErrorMarker 0x189112b0.negError == 12 + 1*0x189112b0.posErrorMarker + -1*0x189112f0.marker + 1*0x189113f0.negError + -1*0x189113f0.posErrorMarker + -1*0x18911a60.marker + 1*0x18925530.marker + 0.5*0x1892dae0.negError + -0.5*0x1892dae0.posErrorMarker + 1*0x1893e080.marker + 0.5*0x18958090.negError + -0.5*0x18958090.posErrorMarker + 1*0x18963640.marker 0x18911370.negError == 9 + -1*0x189112f0.marker + 1*0x18911370.posErrorMarker + 1*0x18925530.marker + 1*0x1892dae0.negError + -1*0x1892dae0.posErrorMarker + 1*0x1893e080.marker + 1*0x18963640.marker 0x189113b0.slackMarker == 2 + -1*0x189107d0.marker + 1*0x18910b90.negError + -1*0x18910b90.posErrorMarker + ........ EXPLETIVES DELETED ......... UITableView:0xca2b000.contentHeight == 36 + 1*0xc221c00.marker UITableView:0xca2b000.contentWidth == 704 + 1*0xc239470.marker UITableView:0xca2b000.minX == 0 + 1*0xc2a23f0.marker + -0.5*0xc2a2590.marker UITableView:0xca2b000.minY == 0 + 1*0xc2a25d0.marker + -0.5*0xc2a2630.marker UITableViewCellContentView:0x18ab13d0.Height == 174 + 1*0x18abd4f0.marker UITableViewCellContentView:0x18ab13d0.Width == 704 + 1*0x18abd470.marker ........ EXPLETIVES DELETED ......... <NSAutoresizingMaskLayoutConstraint:0x18988bc0 h=-&- v=-&- UIView:0x18911e50.midY == UIView:0x1892d0c0.midY> Marker:0x18988bc0.marker <NSAutoresizingMaskLayoutConstraint:0x18994b40 h=-&- v=-&- UIView:0xc4a6fb0.midX == UIView:0xc4b4990.midX> Marker:0x18994b40.marker <NSAutoresizingMaskLayoutConstraint:0x18998480 h=-&- v=-&- UIView:0x18915180.width == UIView:0xc4c5970.width> Marker:0x18998480.marker <NSAutoresizingMaskLayoutConstraint:0x18aae320 h=--& v=--& TapSectionalTableViewCell:0x18a3d270.midX == + 352> Marker:0x18aae320.marker <NSAutoresizingMaskLayoutConstraint:0x18aae410 h=--& v=--& H:[TapSectionalTableViewCell:0x18a3d270(704)]> Marker:0x18aae410.marker <NSAutoresizingMaskLayoutConstraint:0x18aae450 h=--& v=--& TapSectionalTableViewCell:0x18a3d270.midY == + 144> Marker:0x18aae450.marker ........ EXPLETIVES DELETED ......... <NSAutoresizingMaskLayoutConstraint:0xc2de2f0 h=--& v=--& TapGenericCollectionCell:0xc2ac500.midX == + 499> Marker:0xc2de2f0.marker <NSAutoresizingMaskLayoutConstraint:0xc2de3b0 h=--& v=--& V:[TapGenericCollectionCell:0xc2ac500(34)]> Marker:0xc2de3b0.marker <NSAutoresizingMaskLayoutConstraint:0xc2de430 h=-&- v=-&- UIView:0x18953f80.height == UIView:0xc2acb20.height> Marker:0xc2de430.marker <NSAutoresizingMaskLayoutConstraint:0xc2de520 h=-&- v=-&- UIView:0x18923af0.height == UIView:0xc2ae570.height> Marker:0xc2de520.marker <NSAutoresizingMaskLayoutConstraint:0xc2de560 h=--& v=--& H:[TapGenericCollectionCell:0xc2ac500(280)]> Marker:0xc2de560.marker ........ EXPLETIVES DELETED ......... <NSContentSizeLayoutConstraint:0xc2f5730 H:[_UIBaselineLayoutStrut:0x18994a30(0)] Hug:250 CompressionResistance:750> Marker:0xc2f5730.posErrorMarker <NSContentSizeLayoutConstraint:0xc2f5730 H:[_UIBaselineLayoutStrut:0x18994a30(0)] Hug:250 CompressionResistance:750> Marker:0xc2f5730.posErrorMarker <NSContentSizeLayoutConstraint:0xc2f5770 V:[_UIBaselineLayoutStrut:0x18994a30(18)] Hug:250 CompressionResistance:750> Marker:0xc2f5770.posErrorMarker internal error. Cannot find an outgoing row head for incoming head UIView:0x189712b0.Width, which should never happen.' 
 /**** BEGIN Individual Field Controller - This code is from the base individual field controller used in our editable form collection *****/ - (void)viewDidLoad { [super viewDidLoad]; self.view.clipsToBounds = YES; self.view.opaque = YES; CGRect viewFrame = self.view.frame; viewFrame.size = [self defaultFieldSize]; self.view.frame = viewFrame; if (self.backgroundColor) { self.view.backgroundColor = self.backgroundColor; } else { self.view.backgroundColor = [UIColor whiteColor]; } [self createLabelAndField]; [self setLabelAndFieldContraints]; [self.view addConstraints:self.labelValueConstraints]; [self.view setNeedsUpdateConstraints]; } - (void)createLabelAndField { [self removeLabelAndField]; UILabel *label = [[UILabel alloc] init]; label.font = self.labelFont; label.textColor = self.labelColor; label.lineBreakMode = NSLineBreakByWordWrapping; label.textAlignment = NSTextAlignmentLeft; label.adjustsFontSizeToFitWidth = NO; label.numberOfLines = 0; if (self.backgroundColor) { label.backgroundColor = self.backgroundColor; } else { label.backgroundColor = [UIColor whiteColor]; } [self.view addSubview:label]; self.label = label; /// EXAMPLE valueView initialization from a subclass that handles long text TapEditableTextView *textView = [[TapEditableTextView alloc] init]; if (self.hasLabelOverValue) { textView.shouldMimicTextField = NO; } else { textView.shouldMimicTextField = YES; } textView.delegate = self; textView.keyboardType = UIKeyboardTypeDefault; textView.font = self.valueFont; textView.textColor = self.valueColor; textView.textAlignment = NSTextAlignmentLeft; textView.normalBackgroundColor = self.backgroundColor; textView.editable = NO; textView.textLines = self.textLines; self.valueTextView = textView; self.valueView = textView; [self.view addSubview:textView]; } - (void)removeLabelAndField { [self clearConstraints]; if (self.label) { [self.label removeFromSuperview]; self.label = nil; } if (self.valueView) { [self.valueView removeFromSuperview]; self.valueView = nil; } } - (void)clearConstraints { if (self.isViewLoaded && self.labelValueConstraints) { [self.view removeConstraints:self.labelValueConstraints]; } self.labelValueConstraints = nil; self.labelToValueHorizConstraint = nil; self.valueWidthConstraint = nil; } // This is called in our field viewDidLoad, after we've created our label and valueView (UITextField, UITextView, etc) - (void)setLabelAndFieldContraints { [self clearConstraints]; self.labelValueConstraints = [NSMutableArray array]; self.label.translatesAutoresizingMaskIntoConstraints = NO; self.valueView.translatesAutoresizingMaskIntoConstraints = NO; NSLayoutConstraint *constraint = nil; constraint = [NSLayoutConstraint constraintWithItem:self.label attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeft multiplier:1.0f constant:self.labelValueGap]; constraint.priority = UILayoutPriorityRequired; [self.labelValueConstraints addObject:constraint]; constraint = [NSLayoutConstraint constraintWithItem:self.label attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0f constant:0]; constraint.priority = 550; [self.labelValueConstraints addObject:constraint]; constraint = [NSLayoutConstraint constraintWithItem:self.label attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0]; constraint.priority = 400; [self.labelValueConstraints addObject:constraint]; constraint = [NSLayoutConstraint constraintWithItem:self.valueView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0f constant:0]; constraint.priority = UILayoutPriorityRequired; [self.labelValueConstraints addObject:constraint]; constraint = [NSLayoutConstraint constraintWithItem:self.valueView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0]; constraint.priority = 499; [self.labelValueConstraints addObject:constraint]; constraint = [NSLayoutConstraint constraintWithItem:self.valueView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeRight multiplier:1.0f constant: -(kDisclosureWidth + self.labelValueGap) ]; constraint.priority = 901; [self.labelValueConstraints addObject:constraint]; constraint = [NSLayoutConstraint constraintWithItem:self.valueView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:self.label attribute:NSLayoutAttributeTrailing multiplier:1.0f constant:self.labelValueGap]; constraint.priority = UILayoutPriorityDefaultHigh + 1; [self.labelValueConstraints addObject:constraint]; self.labelToValueHorizConstraint = constraint; constraint = [NSLayoutConstraint constraintWithItem:self.label attribute:NSLayoutAttributeBaseline relatedBy:NSLayoutRelationEqual toItem:self.valueView attribute:NSLayoutAttributeBaseline multiplier:1.0f constant:0.f]; constraint.priority = 600; [self.labelValueConstraints addObject:constraint]; constraint = [NSLayoutConstraint constraintWithItem:self.valueView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeWidth multiplier:(1.f - self.labelWidthPercentage) constant:0]; constraint.priority = 305; [self.labelValueConstraints addObject:constraint]; self.valueWidthConstraint = constraint; [self setCompressionAndHuggingForLabelView:self.label]; [self setCompressionAndHuggingForValueView:self.valueView]; } - (void)setCompressionAndHuggingForLabelView:(UILabel *)labelView { if (!labelView) { return; } [labelView setContentCompressionResistancePriority:510 forAxis:UILayoutConstraintAxisHorizontal]; [labelView setContentCompressionResistancePriority:UILayoutPriorityDefaultHigh forAxis:UILayoutConstraintAxisVertical]; [labelView setContentHuggingPriority:450 forAxis:UILayoutConstraintAxisHorizontal]; [labelView setContentHuggingPriority:UILayoutPriorityDefaultHigh forAxis:UILayoutConstraintAxisVertical]; } - (void)setCompressionAndHuggingForValueView:(UIView *)valueView { if (!valueView) { return; } [valueView setContentCompressionResistancePriority:509 forAxis:UILayoutConstraintAxisHorizontal]; [valueView setContentCompressionResistancePriority:UILayoutPriorityDefaultHigh forAxis:UILayoutConstraintAxisVertical]; [valueView setContentHuggingPriority:300 forAxis:UILayoutConstraintAxisHorizontal]; [valueView setContentHuggingPriority:650 forAxis:UILayoutConstraintAxisVertical]; } /****** END Individual Field Controller ******/ 
+50
ios automatic-ref-counting autolayout
Jul 16 '13 at 22:59
source share
13 answers

I had an extensive conversation with an Apple engineer about this failure.

Here are the two most likely causes:

  • You have an invalid restriction, for example, view1.left = view2.left + 20 , where view2 unexpectedly zero or has a factor of 0. Be sure to double (and triple) check your limitations to make sure they are true. Here are two examples of problematic restrictions:

     // The first constraint would be a problem if view2 were nil [NSLayoutConstraint constraintWithItem:view1 attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:view2 attribute:NSLayoutAttributeBottom multiplier:1 constant:20]; // The second constraint is a problem because the 0 multiplier causes view2 to be "lost" [NSLayoutConstraint constraintWithItem:view1 attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:view2 attribute:NSLayoutAttributeBottom multiplier:0 constant:5]; 
  • You get an error in the internal layout mechanism of the main flag associated with the accumulated loss of precision with floating point. When you crashed, how you can know that this is the case is to search the log for large (large) exceptions in the console for a very small (almost zero) floating point number, for example:

<505:-7.45058e-08>*PWPlotLegendEntryView:0x600000582be0.Height{id: 34609} +

(Search for e- in the console output to find such small numbers.) This number ( -7.45058e-08 in this case) represents the coefficient at that particular point in time, while the internal engine allows restrictions. In this case, the number should be exactly 0, but due to the way the auto-linking mechanism performs calculations with floating-point numbers, it has become an extremely tiny negative number, which blows everything up. If you can find such a quantity in the output, you know that you got into this error.

How can you get around this problem?

Changing the order of adding (activating) constraints can lead to a change in the order of calculations in the internal engine, which as a result can lead to the disappearance of this problem, since mathematics is performed without any problematic loss of accuracy.

This issue occurs more often when you change the content compression resistance or prioritize content for views, so try commenting on any code that does this to see if it caused an error or reordered it will happen sooner or later in your installation code restriction.

More about my specific case:

I ran into this crash on iOS. The steps to reproduce it were very interesting:

  • The view controller containing the table view was clicked on the screen (in the navigation controller).
  • There should be enough cells in the table view so that they do not all correspond to the visible area, then it had to be scrolled to the last cell, and then adjusted a little (presumably, this caused reuse of the cells, which caused this problem).
  • Then, when the view controller containing the table view was removed from the navigation stack immediately after the pop animation completed, the application crashes at the point where the view controller view was removed from the view hierarchy.

After a lot of trial and error, I was able to single out the problem of one specific thing: set the compression resistance of the content and hug the priorities for UIImageView in each of the cells of the table. In this case, the image representation is positioned using an automatic layout inside the cell, and in order to achieve the correct layout, the image representation should be precisely its internal size of the content (the size of its image).

This was problematic code:

 // Inside of the UITableViewCell updateConstraints method... [self.imageView setContentCompressionResistancePriority:​UILayoutPriorityRequired forAxis:​UILayoutConstraintAxisHorizontal]; [self.imageView setContentCompressionResistancePriority:​UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical]; [self.imageView setContentHuggingPriority:​UILayoutPriorityRequired forAxis:​UILayoutConstraintAxisHorizontal]; [self.imageView setContentHuggingPriority:​UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical]; 

Removing the above code and replacing it with 2 restrictions (with mandatory priority) in order to fix the width and height of the image, so that the image size reaches the same result, but avoids a crash. Here's the replacement code (using PureLayout ):

 [self.imageView autoSetDimensionsToSize:self.imageView.image.size]; 

I also found that simply moving the problematic 4 lines to another place in my restriction installation code solved the problem, apparently because it significantly changed the order of the calculations to prevent the problematic loss of precision.

+84
Dec 04 '14 at 4:09
source share

Removal Problem - One Opportunity

Your code that works with automatic linking may well work in the main thread, but one of the blocks that runs in the background and uses your view (perhaps indirectly) may contain a strong link to the view or to one of its owners, for example , seemingly a controller (this is the default behavior of Objective-C blocks). When such a block is launched and freed in the background, strong links that it captures are freed in the same queue, and you may encounter a well-known delete problem.

  • In your view controller, make sure that you use a weak reference to self in all blocks that do not need a strong reference (and can be run in the background). You can declare it as follows: __weak typeof(self) weakSelf = self; before the block - and use weakSelf inside the block.

  • The same goes for any local variables that contain references to your views - make sure their values ​​are fixed as weak references.

Another opportunity

In my work, I ran into a similar problem in iOS 6 when covert viewing was involved in the layout. Removing the view from the hierarchy ( -[UIView removeFromSuperview] ) instead of setting the hidden property to YES fixes the problem for me.

+12
Dec 02 '13 at 20:05
source share

Had the same problem, solved it by removing restrictions one by one in IB until the accident was resolved. This narrowed him to an insulting restriction. Then I restored the specified restriction, but changed the position:

enter image description here

You can be happy and be able to solve your AL problems as easily.

+3
Mar 31 '15 at 3:04
source share

To make @smileyborg's wonderful answer more effective:

This can happen if you have any restrictions with multipliers that could suffer from floating point problems.

To solve:

  • Go to all your restrictions that have multipliers (in the layout code or manually edit the / nib storyboard and search for multiplier= ).
  • If the multiplier is not the “beautiful” power of the two floats, translate it to the nearest one (you can use a floating point calculator )

In an easy way to do 2, you need to enter the number and calculator you need, and then turn off the bits of lower accuracy in the mantissa until the value matches the rounded decimal value at the bottom of the calculator.

+2
Mar 08 '16 at 22:14
source share

For those who encounter this problem in any version of iOS> 8.0, Apple docs claim to use the "active" property in NSLayoutConstraint, and not the removeConstraint / addConstraint function in UIView. Apple Docs Documentation Link

+2
Apr 15 '16 at 22:04
source share

In my case, it was a proportional width limit with a factor of 8: 9. I changed it to 7: 9 and it worked.

By the way, the easiest way to find the restriction is to start deleting views from the view controller. Do this using the binary algorithm :) delete half of the views, then half of the half, which will cause the application to crash, etc.

+1
Jun 05 '15 at 13:28
source share

For me, the problem was that I removed the restriction at the time that suited me, after calling dequeueReusableCellWithReuseIdentifier when setting the properties of my UICollectionViewCell. The solution was to call instead:

  [_myUICollectionViewCell setNeedsUpdateConstraints]; 

and override:

  -(void)updateConstraints 

and make my mess there. It seems you cannot just remove the restrictions whenever you want.

+1
Jul 16 '15 at 19:41
source share

I just stumbled upon the same error in OSX Mavericks with the OSX application that I am developing, but unlike other answers, I definitely do not have any other threads interacting with the user interface objects, and the hierarchy of representations in question is also definitely visible. I do not use blocks either. Unusually, the problem disappeared when I removed the vertical restriction on NSTextField.

FWIW is a problematic look whose removal from its supervisor causes an “internal error. Unable to find outgoing header line for incoming head”. An error is one of many sidebar controls that together represent the properties of objects in the main view, which can be cut, copied, created, etc. This means that the user can quickly insert new objects into the main view, that is, the sidebar controls are destroyed, and new ones are also created very quickly. Of course, with everything in the main stream this should not change, but it seems.

The exact limitation causing the problems was

[self addConstraint: [NSLayoutConstraint constraintWithItem: control Attribute: NSLayoutAttributeHeight relatedBy: NSLayoutRelationEqual toItem: other Attribute: NSLayoutAttributeHeight Multiplier: 1.4 constant: 0.0]];

where the control is the (editable) NSTextField causing the problems and the “other” is the other (non-editable) NSTextField label.

0
Mar 16 '14 at 17:10
source share

I am having a problem with the MZFormSheetController pod: https://github.com/m1entus/MZFormSheetController/issues/78

This code failed:

 [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 the declaration of the sharePanel property:

 @property (weak, nonatomic) IBOutlet UIView *sharePanel; 
0
Apr 2 '14 at 16:07
source share

I get this crash when I call removeConstraints: with argument nil.

0
Dec 02 '14 at 15:09
source share

I got this crash when I still have a missing restriction in wAnyhAny mode, the correction of which fixed the error.

0
Aug 27 '15 at 12:02
source share

As the other answers in this thread indicate that this is somehow a wrong startup / contraindication issue, although it seems to be very subtle regarding what qualifies as “invalid”.

Fortunately, I have not made many changes since my last commit and was able to track breaking changes. For me, the problem was 10 horizontal UIImageView with equal width and fixed 2: 3 aspect ratio.

It seemed that the accident occurred after exiting the UIViewController containing this image line. Each UIImageView parameter UIImageView set to UIViewContentModeScaleAspectFill . ( UIImage ), , , . .

, ... , iPhone 4 iOS 7.1.2. iPhone 4s iOS 9.1 . phsyical iPhone 5 iOS 9.1.

, -

0
01 . '15 23:03
source share

According to Apple documentation:

iOS 8.0 YES addConstraint:. .

 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
05 . '16 13:28
source share



All Articles