自动版式:removeFromSuperview / removeConstraints抛出异常和硬崩溃 [英] AutoLayout: removeFromSuperview / removeConstraints throws exception and crashes hard

查看:1351
本文介绍了自动版式:removeFromSuperview / removeConstraints抛出异常和硬崩溃的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们使用自动布局限制选择,主要是相对于可编辑的字段元素(UITextView的,的UITextField,通常情况下)标签的位置。但是,由于这些领域实现汽车的布局,我们看到一个讨厌的异常和崩溃,每当我们卸载的意见,取消分配等例外情况发生,因为它是在尝试卸载之前删除从视图的限制。

我们的视图/控制器层次是这样:

 的UITableViewController(平原风格,但与细胞的外观模仿分组样式)
- >的UITableViewCell
----> UIViewController的(可编辑的表格容器)
------> UICollectionViewController(编辑表格)
--------> UICollectionViewCell
----------->的UIViewController(编辑字段)
-------------->的UILabel(字段标签)** HAS约束**
--------------> UITextView的/的UITextField(字段的值)** HAS约束**

很多时候被释放上层表格单元格时/更换/重装,我们看到一个巨大的异常,然后崩溃,因为它正试图释放/卸载内的视图层次。

我试图通过捕捉异常(没有帮助),以减轻飞机坠毁,也通过强制删除所有受影响的看法的约束和所有释放/卸载(在之前的子视图viewWillDisappear:),它似乎并没有帮助。我甚至试过一个消除这些制约因素之一,看看是否有一特别是造成了麻烦,但所有的人都吹起来的时候,我们调用 removeConstraint: removeConstraints:在preparation为消失的容器

我百思不得其解!下面是我们的例外的一个片段 - 大约3000左右线已斩出来的,所以如果你需要更多的,只是问

 异常而重新分配的观点:{行:
    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 +      ........咒骂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      ........咒骂DELETED .........    < NSAutoresizingMaskLayoutConstraint:0x18988bc0 H = - &安培; - V = - &安培; - 的UIView:0x18911e50.midY ==的UIView:0x1892d0c0.midY>标记:0x18988bc0.marker
    < NSAutoresizingMaskLayoutConstraint:0x18994b40 H = - &安培; - V = - &安培; - 的UIView:0xc4a6fb0.midX ==的UIView:0xc4b4990.midX>标记:0x18994b40.marker
    < NSAutoresizingMaskLayoutConstraint:0x18998480 H = - &安培; - V = - &安培; - 的UIView:0x18915180.width ==的UIView:0xc4c5970.width>标记:0x18998480.marker
    < NSAutoresizingMaskLayoutConstraint:0x18aae320 H = - &安培; V = - &安培; TapSectionalTableViewCell:0x18a3d270.midX == + 352>标记:0x18aae320.marker
    < NSAutoresizingMaskLayoutConstraint:0x18aae410 H = - &安培; V = - &安培; H:[TapSectionalTableViewCell:0x18a3d270(704)]≥标记:0x18aae410.marker
    < NSAutoresizingMaskLayoutConstraint:0x18aae450 H = - &安培; V = - &安培; TapSectionalTableViewCell:0x18a3d270.midY == + 144 GT;标记:0x18aae450.marker      ........咒骂DELETED .........    < NSAutoresizingMaskLayoutConstraint:0xc2de2f0 H = - &安培; V = - &安培; TapGenericCollectionCell:0xc2ac500.midX == + 499>标记:0xc2de2f0.marker
    < NSAutoresizingMaskLayoutConstraint:0xc2de3b0 H = - &安培; V = - &安培;五:[TapGenericCollectionCell:0xc2ac500(34)]≥标记:0xc2de3b0.marker
    < NSAutoresizingMaskLayoutConstraint:0xc2de430 H = - &安培; - V = - &安培; - 的UIView:0x18953f80.height ==的UIView:0xc2acb20.height>标记:0xc2de430.marker
    < NSAutoresizingMaskLayoutConstraint:0xc2de520 H = - &安培; - V = - &安培; - 的UIView:0x18923af0.height ==的UIView:0xc2ae570.height>标记:0xc2de520.marker
    < NSAutoresizingMaskLayoutConstraint:0xc2de560 H = - &安培; V = - &安培; H:[TapGenericCollectionCell:0xc2ac500(280)]≥标记:0xc2de560.marker      ........咒骂DELETED .........    < NSContentSizeLayoutConstraint:0xc2f5730 H:[_ UIBaselineLayoutStrut:0x18994a30(0)]拥抱:250的COM pressionResistance:750 GT;标记:0xc2f5730.posErrorMarker
    < NSContentSizeLayoutConstraint:0xc2f5730 H:[_ UIBaselineLayoutStrut:0x18994a30(0)]拥抱:250的COM pressionResistance:750 GT;标记:0xc2f5730.posErrorMarker
    < NSContentSizeLayoutConstraint:0xc2f5770五:[_ UIBaselineLayoutStrut:0x18994a30(18)]拥抱:250的COM pressionResistance:750 GT;标记:0xc2f5770.posErrorMarker内部错误。找不到传入头的UIView传出的行头:0x189712b0.Width,这不应该发生。

/ **** BEGIN个人现场控制器 - 这个code是从所使用的基单个字段控制我们可编辑的形式收集***** / - (无效)viewDidLoad中{
    [超级viewDidLoad中];
    self.view.clipsToBounds = YES;
    self.view.opaque = YES;    的CGRect viewFrame = self.view.frame;
    viewFrame.size = [个体经营de​​faultFieldSize]
    self.view.frame = viewFrame;    如果(self.backgroundColor){
        self.view.backgroundColor = self.backgroundColor;
    }
    其他{
        self.view.backgroundColor =的UIColor whiteColor]
    }
    [个体经营createLabelAndField]    [个体经营setLabelAndFieldContraints]    [self.view addConstraints:self.labelValueConstraints];
    [self.view setNeedsUpdateConstraints]
} - (无效){createLabelAndField
    [个体经营removeLabelAndField]    *的UILabel标签= [[的UILabel的alloc]初始化];
    label.font = self.labelFont;
    label.textColor = self.labelColor;
    label.lineBreakMode = NSLineBreakByWordWrapping;
    label.textAlignment = NSTextAlignmentLeft;
    label.adjustsFontSizeToFitWidth = NO;
    label.numberOfLines = 0;    如果(self.backgroundColor){
        label.backgroundColor = self.backgroundColor;
    }
    其他{
        label.backgroundColor =的UIColor whiteColor]
    }    [self.view addSubview:标号];    self.label =标签;
    ///从处理长文本的子类实例初始化valueView    TapEditableTextView *的TextView = [[TapEditableTextView的alloc]初始化];
    如果(self.hasLabelOverValue){
        textView.shouldMimicTextField = NO;
    }
    其他{
        textView.shouldMimicTextField = YES;
    }
    textView.delegate =自我;
    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中];
} - (无效){removeLabelAndField
    [个体经营clearConstraints]    如果(self.label){
        [self.label removeFromSuperview]
        self.label =零;
    }
    如果(self.valueView){
        [self.valueView removeFromSuperview]
        self.valueView =零;
    }
} - (无效){clearConstraints
    如果(self.isViewLoaded&安培;&安培; self.labelValueConstraints){
        [self.view removeConstraints:self.labelValueConstraints];
    }
    self.labelValueConstraints =零;
    self.labelToValueHorizCons​​traint =零;
    self.valueWidthConstraint =零;
}//这就是所谓的在我们的领域的viewDidLoad,我们已经创建了标签和valueView(的UITextField,UITextView的,等等)后,
- (无效){setLabelAndFieldContraints
    [个体经营clearConstraints]    self.labelValueConstraints = [NSMutableArray的阵列]    self.label.translatesAutoresizingMaskIntoConstraints = NO;
    self.valueView.translatesAutoresizingMaskIntoConstraints = NO;    NSLayoutConstraint *约束=零;    约束= [NSLayoutConstraint
                  constraintWithItem:self.label属性:NSLayoutAttributeLeft
                  relatedBy:NSLayoutRelationEqual
                  toItem:self.view属性:NSLayoutAttributeLeft
                  事半功倍:1.0F常数:self.labelValueGap];
    constraint.priority = UILayoutPriorityRequired;
    [self.labelValueConstraints ADDOBJECT:约束];
    约束= [NSLayoutConstraint
                  constraintWithItem:self.label属性:NSLayoutAttributeTop
                  relatedBy:NSLayoutRelationEqual
                  toItem:self.view属性:NSLayoutAttributeTop
                  事半功倍:1.0F常数:0];
    constraint.priority = 550;
    [self.labelValueConstraints ADDOBJECT:约束];
    约束= [NSLayoutConstraint
                  constraintWithItem:self.label属性:NSLayoutAttributeBottom
                  relatedBy:NSLayoutRelationEqual
                  toItem:self.view属性:NSLayoutAttributeBottom
                  事半功倍:1.0F常数:0];
    constraint.priority = 400;
    [self.labelValueConstraints ADDOBJECT:约束];
    约束= [NSLayoutConstraint
                  constraintWithItem:self.valueView属性:NSLayoutAttributeTop
                  relatedBy:NSLayoutRelationEqual
                  toItem:self.view属性:NSLayoutAttributeTop
                  事半功倍:1.0F常数:0];
    constraint.priority = UILayoutPriorityRequired;
    [self.labelValueConstraints ADDOBJECT:约束];
    约束= [NSLayoutConstraint
                  constraintWithItem:self.valueView属性:NSLayoutAttributeBottom
                  relatedBy:NSLayoutRelationEqual
                  toItem:self.view属性:NSLayoutAttributeBottom
                  事半功倍:1.0F常数:0];
    constraint.priority = 499;
    [self.labelValueConstraints ADDOBJECT:约束];
     约束= [NSLayoutConstraint
                  constraintWithItem:self.valueView属性:NSLayoutAttributeRight
                  relatedBy:NSLayoutRelationEqual
                  toItem:self.view属性:NSLayoutAttributeRight
                  事半功倍:1.0F常数: - (kDisclosureWidth + self.labelValueGap)];
     constraint.priority = 901;
     [self.labelValueConstraints ADDOBJECT:约束];
    约束= [NSLayoutConstraint
                  constraintWithItem:self.valueView属性:NSLayoutAttributeLeading
                  relatedBy:NSLayoutRelationGreaterThanOrEqual
                  toItem:self.label属性:NSLayoutAttributeTrailing
                  事半功倍:1.0F常数:self.labelValueGap];
    constraint.priority = UILayoutPriorityDefaultHigh + 1;
    [self.labelValueConstraints ADDOBJECT:约束];
    self.labelToValueHorizCons​​traint =约束;
    约束= [NSLayoutConstraint
                  constraintWithItem:self.label属性:NSLayoutAttributeBaseline
                  relatedBy:NSLayoutRelationEqual
                  toItem:self.valueView属性:NSLayoutAttributeBaseline
                  事半功倍:1.0F常数:0.f];
    constraint.priority = 600;
    [self.labelValueConstraints ADDOBJECT:约束];
    约束= [NSLayoutConstraint
                  constraintWithItem:self.valueView属性:NSLayoutAttributeWidth
                  relatedBy:NSLayoutRelationEqual
                  toItem:self.view属性:NSLayoutAttributeWidth
                  乘数:(1.F - self.labelWidthPercentage)常数:0];
    constraint.priority = 305;
    [self.labelValueConstraints ADDOBJECT:约束];
    self.valueWidthConstraint =约束;
    [自setCom pressionAndHuggingForLabelView:self.label];
    [自setCom pressionAndHuggingForValueView:self.valueView];
} - (无效)setCom pressionAndHuggingForLabelView:(*的UILabel){LABELVIEW
    如果(!LABELVIEW){
        返回;
    }
    [LABELVIEW setContentCom pressionResistancePriority:510 forAxis:UILayoutConstraintAxisHorizo​​ntal];
    [LABELVIEW setContentCom pressionResistancePriority:UILayoutPriorityDefaultHigh forAxis:UILayoutConstraintAxisVertical];
    [LABELVIEW setContentHuggingPriority:450 forAxis:UILayoutConstraintAxisHorizo​​ntal];
    [LABELVIEW setContentHuggingPriority:UILayoutPriorityDefaultHigh forAxis:UILayoutConstraintAxisVertical];
} - (无效)setCom pressionAndHuggingForValueView:(UIView的*)valueView {
    如果(!valueView){
        返回;
    }
    [valueView setContentCom pressionResistancePriority:509 forAxis:UILayoutConstraintAxisHorizo​​ntal];
    [valueView setContentCom pressionResistancePriority:UILayoutPriorityDefaultHigh forAxis:UILayoutConstraintAxisVertical];
    [valueView setContentHuggingPriority:300 forAxis:UILayoutConstraintAxisHorizo​​ntal];
    [valueView setContentHuggingPriority:650 forAxis:UILayoutConstraintAxisVertical];
}/ ****** END个人现场控制器****** /


解决方案

我有一个苹果工程师这个崩溃的(大量)交谈。

下面是两个最可能的原因:


  1. 您有一个无效的约束,如 view1.left = view2.left + 20 ,其中视图2 意外地零,或具有0事半功倍请务必仔细(和三)检查您的约束,以确保它们是正确的。这里是有问题的制约2个例子:

      //第一个约束将是一个问题,如果视图2是零
    [NSLayoutConstraint constraintWithItem:厂景属性:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:视图2属性:NSLayoutAttributeBottom倍数:1不变:20];
    //第二个约束是一个问题,因为0乘数导致视图2被丢失
    [NSLayoutConstraint constraintWithItem:厂景属性:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:视图2属性:NSLayoutAttributeBottom倍数:0不变:5];


  2. 你打与浮点precision的累计损失,在内部基金会自动排版引擎的bug。当你崩溃,你可以知道这种情况的方法是在控制台通过(大)异常日志寻找一个非常小的(几乎为零)浮点数像这样的:


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

(搜索 E - 在控制台输出中找到少数这样的)这个数字( -7.45058e-08 在这种情况下)再presents在这个特别的一点系数在时间上,而内部引擎解决制约。在这种情况下,数应该是恰好为0,但是由于在自动布局引擎执行浮点数的计算的方式,它已成为一个极其微小的负数,而不是该吹一切。如果你能找到在输出这样一个数字,你知道,你已经打了这个bug。

如何才能解决这个问题?

改变所添加(激活)的约束可以结束改变发动机内部​​,其结果可能会导致消失这一问题作为数学而不precision的任何问题的损失进行计算的顺序的顺序

此问题似乎要拿出更加频繁时,你已经改变了内容融为一体pression性或内容拥抱优先的观点,所以尝试注释掉任何code,做那个,看它是否是造成这个错误来发生,或重新排序它在你的约束设置code更早或更晚发生。

关于我的具体情况的更多细节:

我遇到了这个崩溃iOS上。步骤重现它是挺有意思的:


  1. 包含表视图视图控制器被推倒在屏幕上(在导航控制器)。

  2. 表视图必须包含足够的细胞,使他们不适合所有在可见光区域,然后它必须被滚动到最后一个单元格,然后备份位(presumably,这是导致细胞被重用,这是引发这个问题)。

  3. 然后,当包含表视图的视图控制器,弹出导航堆栈后,立即弹出动画完成的应用程序将在其视图控制器的视图从视图层次结构中移除该点崩溃。

大量的试验和错误后,我能够把问题隔离到一个特定的事情:设置内容融为一体pression性和放大器;拥抱了的UIImageView 在每个表视图细胞的重点。在这种情况下,图像视图正在使用自动布局在细胞内的位置,并能实现正确的布局中的图像视图必须准确其内在含量的大小(其图像的大小)

这是有问题的code:

  //里面的UITableViewCell的updateConstraints方法...[self.imageView setContentCom pressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizo​​ntal];
[self.imageView setContentCom pressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
[self.imageView setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizo​​ntal];
[self.imageView setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];

删除上述code和2约束取代它(在需要的优先级),以固定宽度放大器;图像视图的图像的尺寸的高度达到相同的结果,但避免了碰撞。这里的更换code(使用 PureLayout ):

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

我还发现,只是移动有问题的4条线路到一个不同的地方在我的约束设置code解决了这个问题,presumably因为这改变了计算的顺序足以prevent的问题损失precision。

We use auto layout constraints selectively, primarily to position labels in relation to editable field elements (UITextView, UITextField, typically). However, since implementing auto layout for these fields, we're seeing a nasty exception and crash whenever we're unloading views, deallocating, etc. The exceptions are happening as it's attempting to remove the constraints from a view before unloading it.

Our view/controller hierarchy is as such:

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 upper level table cells are being deallocated/replaced/reloaded, we see a huge exception and then crash as it's trying to deallocate/unload the view hierarchy within.

I've attempted to mitigate the crash by catching the exception (no help) and also by forcefully removing all of the constraints on the affected view and all of the subviews prior to deallocation/unload (in viewWillDisappear:) and it doesn't seem to help. I've even tried to remove these constraints one by one to see if there's one in particular that's causing the trouble but all of them are blowing up when we call removeConstraint: or removeConstraints: on a container in preparation for disappearing.

I'm baffled! Here's a snippet of our exception -- roughly about 3000 lines have been chopped out of it, 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's 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 ******/

解决方案

I had an (extensive) conversation with an Apple engineer about this crash.

Here are the two most probable causes:

  1. You have an invalid constraint, such as view1.left = view2.left + 20 where view2 is unexpectedly nil, or has a multiplier of 0. Be sure to double (and triple) check your constraints to make sure that they are correct. Here are 2 examples of problematic constraints:

    // 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];
    

  2. You're hitting a bug in the internal Foundation auto layout engine related to accumulated loss of floating point precision. When you've crashed, the way you can know that this is the case is to search through the (large) exception log in the console for a very small (nearly zero) floating point number such as this:

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

(Search for e- in the console output to find small numbers like this.) This number (-7.45058e-08 in this case) represents the coefficient at this particular point in time while the internal engine is solving constraints. In this case, the number is supposed to be exactly 0, but due to the way the auto layout engine does calculations with floating point numbers it has become an extremely tiny negative number instead which blows everything up. If you can find such a number in the output, you know that you've hit this bug.

How can you work around this issue?

Changing the order that you add (activate) constraints can end up changing the order of calculations in the internal engine, which as a result can cause this issue to disappear as the math is done without any problematic loss of precision.

This issue seems to come up more frequently when you have changed the content compression resistance or content hugging priorities for views, so try commenting out any code that does that to see if it's causing this bug to happen, or re-ordering it to happen earlier or later in your constraint setup code.

More details about my specific case:

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

  1. A view controller containing a table view was pushed on screen (in a navigation controller).
  2. The table view had to contain enough cells so they didn't all fit in the visible area, then it had to be scrolled to the last cell and then back up a bit (presumably, this was causing cells to be reused, which was triggering this issue).
  3. Then, when the view controller containing the table view was popped off the navigation stack, immediately after the pop animation completed the app would crash at the point where the view controller's view was removed from the view hierarchy.

After a lot of trial and error I was able to isolate the issue to one specific thing: setting the content compression resistance & hugging priorities for a UIImageView in each of the table view cells. In this case, the image view is being positioned using Auto Layout inside the cell, and to achieve the correct layout the image view needs to be exactly its intrinsic content size (the size of its image).

This was the problematic code:

// Inside of the UITableViewCell's 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 constraints (at Required priority) to fix the width & height of the image view to the image's size achieved the same result, but avoided the crash. Here's the replacement code (using PureLayout):

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

I also found that just moving the problematic 4 lines to a different place in my constraint setup code resolved the issue, presumably because this changed the order of calculations sufficiently to prevent the problematic loss of precision.

这篇关于自动版式:removeFromSuperview / removeConstraints抛出异常和硬崩溃的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆