Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Crash in iOS 8 when remove a view from UIStackView #35

Open
WeeTom opened this issue Jun 21, 2016 · 4 comments
Open

Crash in iOS 8 when remove a view from UIStackView #35

WeeTom opened this issue Jun 21, 2016 · 4 comments

Comments

@WeeTom
Copy link

WeeTom commented Jun 21, 2016

状况如下:

  1. iOS 8 模拟器
  2. StoryBoard 布局好了,一个StackView上有3个等长Button
  3. 在ViewController viewDidLoad/viewDidAppear 时,将一个按钮 removeFromSuperView
    崩溃~
    iOS 9下没问题~

以下Log

2016-06-21 15:40:41.868 Mingdao[73952:20315626] The view hierarchy is not prepared for the constraint: <NSLayoutConstraint:0x7f00c1d0 UIButton:0x79ecc510.leading == UIButton:0x7abcd710.trailing>
When added to a view, the constraint's items must be descendants of that view (or the view itself). This will crash if the constraint needs to be resolved before the view hierarchy is assembled. Break on -[UIView _viewHierarchyUnpreparedForConstraint:] to debug.
2016-06-21 15:40:41.868 Mingdao[73952:20315626] *** Assertion failure in -[UIStackView _layoutEngine_didAddLayoutConstraint:roundingAdjustment:mutuallyExclusiveConstraints:], /SourceCache/UIKit_Sim/UIKit-3347.44.2/NSLayoutConstraint_UIKitAdditions.m:560
2016-06-21 15:40:41.881 Mingdao[73952:20315626] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Impossible to set up layout with view hierarchy unprepared for constraint.'
*** First throw call stack:
(
0 CoreFoundation 0x01498746 __exceptionPreprocess + 182
1 libobjc.A.dylib 0x04524a97 objc_exception_throw + 44
2 CoreFoundation 0x014985da +[NSException raise:format:arguments:] + 138
3 Foundation 0x01f75720 -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 118
4 UIKit 0x032f22c1 __120-[UIView(UIConstraintBasedLayout) _layoutEngine_didAddLayoutConstraint:roundingAdjustment:mutuallyExclusiveConstraints:]_block_invoke_2 + 203
5 UIKit 0x032f2184 -[UIView(UIConstraintBasedLayout) _layoutEngine_didAddLayoutConstraint:roundingAdjustment:mutuallyExclusiveConstraints:] + 394
6 UIKit 0x032f2507 -[UIView(UIConstraintBasedLayout) _tryToAddConstraintWithoutUpdatingConstraintsArray:roundingAdjustment:mutuallyExclusiveConstraints:] + 61
7 UIKit 0x032f265c -[UIView(UIConstraintBasedLayout) _tryToAddConstraint:roundingAdjustment:mutuallyExclusiveConstraints:] + 281
8 UIKit 0x032f2854 -[UIView(UIConstraintBasedLayout) nsli_addConstraint:] + 56
9 UIKit 0x032f2814 -[UIView(UIConstraintBasedLayout) _addConstraint:] + 218
10 UIKit 0x032f2735 -[UIView(UIConstraintBasedLayout) addConstraint:] + 40
11 Mingdao 0x005555a0 -[FDStackViewDistributionLayoutArrangement resetFillEffect] + 1632
12 Mingdao 0x00557589 -[FDStackViewDistributionLayoutArrangement resetAllConstraints] + 73
13 Mingdao 0x00557b3d -[FDStackViewDistributionLayoutArrangement updateCanvasConnectionConstraintsIfNecessary] + 45
14 Mingdao 0x0055893d -[FDStackViewLayoutArrangement updateArrangementConstraints] + 45
15 Mingdao 0x0055076d -[FDStackView updateLayoutArrangements] + 221
16 Mingdao 0x00550800 -[FDStackView updateConstraints] + 48
17 UIKit 0x032ff5a4 -[UIView(AdditionalLayoutSupport) _internalUpdateConstraintsIfNeededAccumulatingViewsNeedingSecondPassAndViewsNeedingBaselineUpdate:] + 300
18 UIKit 0x032ff804 -[UIView(AdditionalLayoutSupport) _updateConstraintsIfNeededAccumulatingViewsNeedingSecondPassAndViewsNeedingBaselineUpdate:] + 127
19 UIKit 0x032ff77f __UIViewRecursionHelper + 41
20 CoreFoundation 0x0138b529 CFArrayApplyFunction + 57
21 UIKit 0x032ff527 -[UIView(AdditionalLayoutSupport) _internalUpdateConstraintsIfNeededAccumulatingViewsNeedingSecondPassAndViewsNeedingBaselineUpdate:] + 175
22 UIKit 0x032ff804 -[UIView(AdditionalLayoutSupport) _updateConstraintsIfNeededAccumulatingViewsNeedingSecondPassAndViewsNeedingBaselineUpdate:] + 127
23 UIKit 0x032ff77f __UIViewRecursionHelper + 41
24 CoreFoundation 0x0138b529 CFArrayApplyFunction + 57
25 UIKit 0x032ff527 -[UIView(AdditionalLayoutSupport) _internalUpdateConstraintsIfNeededAccumulatingViewsNeedingSecondPassAndViewsNeedingBaselineUpdate:] + 175
26 UIKit 0x032ff837 __125-[UIView(AdditionalLayoutSupport) _updateConstraintsIfNeededAccumulatingViewsNeedingSecondPassAndViewsNeedingBaselineUpdate:]_block_invoke + 43
27 Foundation 0x01ef1077 -[NSISEngine withBehaviors:performModifications:] + 150
28 Foundation 0x01ef45cf -[NSISEngine withAutomaticOptimizationDisabled:] + 48
29 UIKit 0x032fefab -[UIView(AdditionalLayoutSupport) _withAutomaticEngineOptimizationDisabledIfEngineExists:] + 64
30 UIKit 0x032ff804 -[UIView(AdditionalLayoutSupport) _updateConstraintsIfNeededAccumulatingViewsNeedingSecondPassAndViewsNeedingBaselineUpdate:] + 127
31 UIKit 0x032ffd96 __60-[UIView(AdditionalLayoutSupport) updateConstraintsIfNeeded]_block_invoke + 105
32 Foundation 0x01ef1077 -[NSISEngine withBehaviors:performModifications:] + 150
33 Foundation 0x01ef45cf -[NSISEngine withAutomaticOptimizationDisabled:] + 48
34 UIKit 0x032fefab -[UIView(AdditionalLayoutSupport) _withAutomaticEngineOptimizationDisabledIfEngineExists:] + 64
35 UIKit 0x032ff9ec -[UIView(AdditionalLayoutSupport) updateConstraintsIfNeeded] + 248
36 UIKit 0x0330024d -[UIView(AdditionalLayoutSupport) _updateConstraintsAtEngineLevelIfNeeded] + 191
37 UIKit 0x02c0adaf -[UIView(Hierarchy) layoutBelowIfNeeded] + 393
38 UIKit 0x02c0ac11 -[UIView(Hierarchy) layoutIfNeeded] + 83
39 UIKit 0x02d22bc5 -[UINavigationController _layoutViewController:] + 1154
40 UIKit 0x02d21d41 -[UINavigationController _layoutTopViewController] + 261
41 UIKit 0x02d26fd9 -[UINavigationController _tabBarControllerDidFinishShowingTabBar:isHidden:] + 164
42 UIKit 0x02d377d0 -[UITabBarController animationDidStop:finished:context:] + 218
43 UIKit 0x02d38771 __56-[UITabBarController _hideBarWithTransition:isExplicit:]_block_invoke503 + 267
44 UIKit 0x033f3f0b -[_UIViewControllerTransitionCoordinator _applyBlocks:releaseBlocks:] + 198
45 UIKit 0x033f05c0 -[_UIViewControllerTransitionContext _runAlongsideCompletions] + 122
46 UIKit 0x033f02dc -[_UIViewControllerTransitionContext completeTransition:] + 142
47 UIKit 0x02b73310 __53-[_UINavigationParallaxTransition animateTransition:]_block_invoke93 + 724
48 UIKit 0x02c1096e -[UIViewAnimationBlockDelegate _didEndBlockAnimation:finished:context:] + 318
49 UIKit 0x02bf4162 -[UIViewAnimationState sendDelegateAnimationDidStop:finished:] + 206
50 UIKit 0x02bf44d2 -[UIViewAnimationState animationDidStop:finished:] + 80
51 QuartzCore 0x02907571 _ZN2CA5Layer23run_animation_callbacksEPv + 307
52 libdispatch.dylib 0x0574ebef _dispatch_client_callout + 14
53 libdispatch.dylib 0x057346bb _dispatch_main_queue_callback_4CF + 993
54 CoreFoundation 0x013f18ee CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE + 14
55 CoreFoundation 0x013af5f0 __CFRunLoopRun + 2256
56 CoreFoundation 0x013aea5b CFRunLoopRunSpecific + 443
57 CoreFoundation 0x013ae88b CFRunLoopRunInMode + 123
58 GraphicsServices 0x076342c9 GSEventRunModal + 192
59 GraphicsServices 0x07634106 GSEventRun + 104
60 UIKit 0x02b860b6 UIApplicationMain + 1526
61 Mingdao 0x002c86aa main + 138
62 libdyld.dylib 0x05779ac9 start + 1
63 ??? 0x00000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException

@wujianbotju
Copy link

我也遇到了同样的问题,请问您解决了吗?

@WeeTom
Copy link
Author

WeeTom commented Nov 15, 2016

没解决,放弃了。

wujianbotju [email protected]于2016年11月15日周二 下午2:31写道:

我也遇到了同样的问题,请问您解决了吗?


You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
#35 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/ABvhQYIhgwt7C-LGx6eMSrDZXPYYo8dsks5q-VHSgaJpZM4I6chS
.

@wujianbotju
Copy link

wujianbotju commented Nov 15, 2016

稍微调试了一下,问题的原因在于FDStackView的代码实现和系统原生的UIStackView的实现不一致,而且FDStackView没有正确处理FDStackView子view的removeFromSuperView的调用。

系统原生的UIStackView的removeArrangedSubview方法的注释是这样的:
Removes the provided view from the stack’s array of arranged subviews.
This method removes the provided view from the stack’s arrangedSubviews array. The view’s position and size will no longer be managed by the stack view. However, this method does not remove the provided view from the stack’s subviews array; therefore, the view is still displayed as part of the view hierarchy.
To prevent the view from appearing on screen after calling the stack’s removeArrangedSubview: method, explicitly remove the view from the subviews array by calling the view’s removeFromSuperview method, or set the view’s hidden property to YES.
简单翻译下就是说:对UIStackView中的子view调用removeArrangedSubview方法,UIStackView只是不再管理此view的布局了,但是此view还是会存在于UIStackView的subviews中(且仍然会显示在屏幕上,我实际测试了一下确实是显示在屏幕的左上角的,当然可能不同的版本会有些许的差别),如果想要阻止此view的显示,对此view明确地调用removeFromSuperView或者将其hidden属性设为YES。

但我们看下FDStackView的removeArrangedSubview实现

- (void)removeArrangedSubview:(UIView *)view {
    if (![self.mutableArrangedSubviews containsObject:view] || ![view isDescendantOfView:self]) {
        return;
    }
    [self removeHiddenObserverForView:view];
    [self.mutableArrangedSubviews removeObject:view];
    [view removeFromSuperview];                                      //这儿明显和系统的实现有差别
    [self.alignmentArrangement removeItem:view];
    [self.distributionArrangement removeItem:view];
    [self updateLayoutArrangements];
}
  1. 回到正题,为什么iOS8崩溃,iOS9不崩溃:因为在iOS9会使用系统自带的UIStackView的实现,而在iOS8上会调用FDStackView的实现。
  2. 究竟为什么在iOS8上FDStackView崩溃:对FDStackView的子view调用removeFromSuperView,此view从subviews移除了,却并没有从self.arrangedSubviews中移除。导致计算FDStackView的intrinsicContentSize时,子view的superView为nil但却存在约束。
  3. 如何解决
if (IS_IOS9_OR_GREATER)
{
        //UIStackView的removeArrangedSubview方法只会将其从arrangedSubviews中移除,而xxx依然会显示在屏幕上,因此我们需要调用removeFromSuperview方法
        //更多详情请查看UIStackView的removeArrangedSubview方法说明
        [xxx removeFromSuperview];
}
else
{
        //FDStackView的removeArrangedSubview方法会主动调用[xxx removeFromSuperview];
        [fdStackView removeArrangedSubview:xxx];
}

@monkiyang
Copy link

@wujianbotju 按你的方法解决了,谢谢!!

github-xiaogang referenced this issue Mar 8, 2017
我在TableViewCell中使用StackView 重用时会出现重复添加view的问题,发现在addArrangedSubView 或
insertArrangedSubview:atIndex: 中 调用了 [self addSubview:view] 或 [self
insertSubview:view atIndex:stackIndex] 但并没有在removeArrangedSubview:
中删除添加的view
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants