[崩溃] -[MyBaseLayout myValidMargin:subview:calcPos:selfLayoutSize:]
#147 · closed · 2 comments
View on GitHub ↗
场景:
在ViewController中的`- (void)loadView`方法布局,容器是`UIScrollowView`
崩溃栈信息
```
Kernel Triage:
VM - Compressor failed a blocking pager_get
Thread 0 name:
Thread 0 Crashed:
0 libobjc.A.dylib 0x000000019b1025e0 objc_msgSend + 32
1 LeoaoApp 0x0000000105af3dc8 -[MyBaseLayout myValidMargin:subview:calcPos:selfLayoutSize:] + 12631496 (MyBaseLayout.m:2331)
2 LeoaoApp 0x0000000105b30750 -[MyLinearLayout myDoHorzOrientationLayoutWithContext:] + 12879696 (MyLinearLayout.m:982)
3 LeoaoApp 0x0000000105b2b1b4 -[MyLinearLayout calcLayoutSize:subviewEngines:context:] + 12857780 (MyLinearLayout.m:163)
4 LeoaoApp 0x0000000105af0144 -[MyBaseLayout myEstimateLayoutSize:inSizeClass:subviews:] + 12616004 (MyBaseLayout.m:0)
5 LeoaoApp 0x0000000105af5ec0 -[MyBaseLayout myWidthSizeValueOfSubviewEngine:withContext:] + 12639936 (MyBaseLayout.m:2649)
6 LeoaoApp 0x0000000105b2ee44 -[MyLinearLayout myDoHorzOrientationLayoutWithContext:] + 12873284 (MyLinearLayout.m:0)
7 LeoaoApp 0x0000000105b2b1b4 -[MyLinearLayout calcLayoutSize:subviewEngines:context:] + 12857780 (MyLinearLayout.m:163)
8 LeoaoApp 0x0000000105af0144 -[MyBaseLayout myEstimateLayoutSize:inSizeClass:subviews:] + 12616004 (MyBaseLayout.m:0)
9 UIKitCore 0x000000018531dae4 -[_UITAMICAdaptorView updateForAvailableSize] + 124 (_UITAMICAdaptorView.m:111)
10 UIKitCore 0x000000018562ba14 -[_UITAMICAdaptorView _geometryChanged:forAncestor:] + 84 (_UITAMICAdaptorView.m:130)
11 UIKitCore 0x00000001851754c0 -[UIView _notifyGeometryObserversWithChangeInfo:] + 280 (UIView.m:8875)
12 UIKitCore 0x000000018519668c -[UIView(Geometry) setFrame:] + 836 (UIView.m:10170)
13 LeoaoApp 0x0000000105aec794 -[MyBaseLayout setFrame:] + 12601236 (MyBaseLayout.m:1096)
14 LeoaoApp 0x0000000105aeecf4 -[MyBaseLayout doLayoutSubviews] + 12610804 (MyBaseLayout.m:1562)
15 LeoaoApp 0x0000000105aefe64 -[MyBaseLayout layoutSubviews] + 12615268 (MyBaseLayout.m:1722)
16 UIKitCore 0x000000018519ac6c -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 2620 (UIView.m:18320)
17 QuartzCore 0x00000001868f4280 CA::Layer::layout_if_needed(CA::Transaction*) + 536 (CALayer.mm:10036)
18 QuartzCore 0x00000001868e6aa8 CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 144 (CALayer.mm:2478)
19 QuartzCore 0x00000001868fb0b0 CA::Context::commit_transaction(CA::Transaction*, double, double*) + 500 (CAContextInternal.mm:2584)
20 QuartzCore 0x0000000186904174 CA::Transaction::commit() + 680 (CATransactionInternal.mm:449)
21 QuartzCore 0x00000001868e621c CA::Transaction::flush_as_runloop_observer(bool) + 100 (CATransactionInternal.mm:941)
22 UIKitCore 0x0000000185551c28 _UIApplicationFlushCATransaction + 76 (UIApplication.m:0)
23 UIKitCore 0x00000001857ebad8 _UIUpdateSequenceRun + 84 (_UIUpdateSequence.mm:67)
24 UIKitCore 0x0000000185e63294 schedulerStepScheduledMainSection + 144 (_UIUpdateCycleScheduler.m:1204)
25 UIKitCore 0x0000000185e62760 runloopSourceCallback + 60 (_UIUpdateCycleScheduler.m:1292)
26 CoreFoundation 0x0000000182c1e030 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 28 (CFRunLoop.c:1972)
27 CoreFoundation 0x0000000182c2ecf0 __CFRunLoopDoSource0 + 208 (CFRunLoop.c:2016)
28 CoreFoundation 0x0000000182b68ff8 __CFRunLoopDoSources0 + 268 (CFRunLoop.c:2053)
29 CoreFoundation 0x0000000182b6e804 __CFRunLoopRun + 820 (CFRunLoop.c:2951)
30 CoreFoundation 0x0000000182b823c8 CFRunLoopRunSpecific + 600 (CFRunLoop.c:3268)
31 GraphicsServices 0x000000019e39338c GSEventRunModal + 164 (GSEvent.c:2200)
32 UIKitCore 0x0000000185528060 -[UIApplication _run] + 1100 (UIApplication.m:3457)
33 UIKitCore 0x00000001852a5b8c UIApplicationMain + 2124 (UIApplication.m:5013)
34 LeoaoApp 0x0000000105235514 main + 3462420 (main.m:34)
35 dyld 0x0000000108835a24 start + 520 (dyldMain.cpp:876)
```
Comments
从这个崩溃栈以及结合的代码来看,应该是为MyLayoutPos对象设置的最大最小值的类型不被支持导致的:
//约束冲突:无效的边界设置方法
NSCAssert(0, @"Constraint exception!! %@ has invalid lBound or uBound setting", subview);
对于MyLayoutPos中的lBound或者uBound方法来说,只支持最大最小值为具体的某个数字或者另外一个MyLayoutPos对象,而不支持MyLayoutSize对象,问题可能是你设置某个位置的最大最小值是某个尺寸对象,这是不自持的。
从下图看,像是野指针的问题,如果是类型不对应该每次都崩溃,下面是线上灰度,testflight收集到的崩溃。
<img width="1141" alt="B11D840B-B564-458F-AA23-E48A6C1072E7" src="https://user-images.githubusercontent.com/7357189/139418953-ec5b93e6-0023-44aa-8fbe-9355e88f1f22.png">
布局代码
```
- (void)setUpView {
CALayer *bgLayer = [CALayer layer];
bgLayer.backgroundColor = [UIColor lk_colorWithHexString:@"#4A445C"].CGColor;
bgLayer.frame = CGRectMake(0, 0, kScreenWidth, kScreenHeight / 2.0);
[self.view.layer addSublayer:bgLayer];
self.view.backgroundColor = [UIColor lk_colorWithHexString:@"#F5F5F5"];
CGRect rect = self.view.bounds;
rect.origin.y = kNavBarHeight;
rect.size.height -= (kNavBarHeight + kTabBarHeight);
UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:rect];
scrollView.backgroundColor = [UIColor clearColor];
scrollView.delegate = self;
self.scrollView = scrollView;
LKAdjustsScrollViewInsetsNO(scrollView, self);
[self.view addSubview:scrollView];
_loadingView = [[LKLoading alloc] initWithFrame:CGRectMake((rect.size.width - 100) / 2.0, (rect.size.height - 100) / 2.0, 100, 100)];
[self.view addSubview:_loadingView];
/// 容器
MyLinearLayout *contentLayout = [MyLinearLayout linearLayoutWithOrientation:MyOrientation_Vert];
contentLayout.backgroundColor = [UIColor lk_colorWithHexString:@"#F5F5F5"];
contentLayout.padding = UIEdgeInsetsMake(8, 16, 10, 16); //设置布局内的子视图离自己的边距.
contentLayout.myHorzMargin = 0; //同时指定左右边距为0表示宽度和父视图一样宽
contentLayout.heightSize.lBound(scrollView.heightSize, 10, 1);
//高度虽然是自适应的。但是最小的高度不能低于父视图的高度加10.
contentLayout.gravity = MyGravity_Vert_Top | MyGravity_Horz_Stretch;
[scrollView addSubview:contentLayout];
self.contentLayout = contentLayout;
/// 背景
LKRadianView *radianView = [LKRadianView new];
radianView.direction = LKRadianDirectionBottom;
radianView.radian = 10;
radianView.backgroundColor = [UIColor lk_colorWithHexString:@"#4A445C"];
radianView.frame = CGRectMake(0, -1, kScreenWidth, 114);
radianView.useFrame = YES;
[contentLayout insertSubview:radianView atIndex:0];
/// 头部运动数据卡片
MyLinearLayout *topCardLayout = [MyLinearLayout linearLayoutWithOrientation:MyOrientation_Horz];
topCardLayout.myHorzMargin = 0;
topCardLayout.subviewHSpace = 7;
topCardLayout.gravity = MyGravity_Horz_Fill | MyGravity_Vert_Stretch;
topCardLayout.myHeight = MyLayoutSize.wrap;
[contentLayout addSubview:topCardLayout];
self.sportDaysCardView = [LKSportMainSportDataCardView new];
self.sportDaysCardView.weight = 1;
self.sportDaysCardView.myHeight = 120;
[self.sportDaysCardView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onTapSportDays:)]];
self.sportWeightCardView = [LKSportMainHealthDataCardView new];
self.sportWeightCardView.weight = 1;
self.sportWeightCardView.myHeight = 120;
[self.sportWeightCardView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onTapWeight:)]];
[topCardLayout addSubview:self.sportDaysCardView];
[topCardLayout addSubview:self.sportWeightCardView];
//教练
MyRelativeLayout *coachPageViewLayout = [MyRelativeLayout new];
coachPageViewLayout.backgroundColor = UIColor.whiteColor;
coachPageViewLayout.layer.cornerRadius = 6;
coachPageViewLayout.myHeight = 0;
coachPageViewLayout.myTop = 8;
_coachPageViewLayout = coachPageViewLayout;
[contentLayout addSubview:coachPageViewLayout];
LKPagerView *pageView = [LKPagerView new];
pageView.interitemSpacing = 8;
pageView.delegate = self;
pageView.dataSource = self;
pageView.automaticSlidingInterval = 0;
[pageView registerClass:LKSportMainCoachPageViewCell.class forCellWithReuseIdentifier:NSStringFromClass(LKSportMainCoachPageViewCell.class)];
_coachPageView = pageView;
pageView.widthSize.equalTo(coachPageViewLayout.widthSize);
pageView.heightSize.equalTo(coachPageViewLayout.heightSize);
[coachPageViewLayout addSubview:pageView];
LKPageControl *pControl = [LKPageControl new];
pControl.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter;
[pControl setItemSpacing:10 forState:UIControlStateNormal];
[pControl setItemSpacing:18 forState:UIControlStateSelected];
pControl.interitemSpacing = 3;
pControl.hidesForSinglePage = YES;
[pControl setStrokeColor:[UIColor lk_colorWithHexString:@"#F2F2F2"] forState:UIControlStateNormal];
[pControl setFillColor:[UIColor lk_colorWithHexString:@"#F2F2F2"] forState:UIControlStateNormal];
[pControl setStrokeColor:[UIColor lk_colorWithHexString:@"#F2F2F2"] forState:UIControlStateSelected];
[pControl setFillColor:[UIColor lk_colorWithHexString:@"#F2F2F2"] forState:UIControlStateSelected];
UIBezierPath *path11 = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, (10 - 2) / 2.0, 10, 2) cornerRadius:2];
[pControl setPath:path11 forState:UIControlStateNormal];
UIBezierPath *path22 = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, (18 - 2) / 2.0, 18, 2) cornerRadius:2];;
[pControl setPath:path22 forState:UIControlStateSelected];
_coachPageControl = pControl;
pControl.widthSize.equalTo(coachPageViewLayout.widthSize);
pControl.heightSize.equalTo(@2);
pControl.bottomPos.equalTo(coachPageViewLayout.bottomPos).offset(7);
[coachPageViewLayout addSubview:pControl];
/// 运动日历
MyLinearLayout *sportCalendaLayout = [MyLinearLayout linearLayoutWithOrientation:MyOrientation_Vert];
sportCalendaLayout.backgroundColor = [UIColor whiteColor];
sportCalendaLayout.layer.cornerRadius = 8;
sportCalendaLayout.layer.masksToBounds = YES;
sportCalendaLayout.myHorzMargin = 0;
sportCalendaLayout.myHeight = MyLayoutSize.wrap;
sportCalendaLayout.myTop = 12;
sportCalendaLayout.gravity = MyGravity_Horz_Stretch;
_sportCalendaLayout = sportCalendaLayout;
[contentLayout addSubview:sportCalendaLayout];
// logo
MyLinearLayout *logoLayout = [MyLinearLayout linearLayoutWithOrientation:MyOrientation_Horz];
logoLayout.myHorzMargin = 0;
logoLayout.myHeight = MyLayoutSize.wrap;
logoLayout.gravity = MyGravity_Vert_Center | MyGravity_Horz_Between;
logoLayout.padding = UIEdgeInsetsMake(22, 16, 5, 21);
UIImageView *logoImageView = [UIImageView new];
logoImageView.image = [UIImage lk_imageNamed:@"sport_tab_sport_calendar_logo_image" inBundleClass:self.class subBundleName:@"LKSportCalendar"];
logoImageView.mySize = CGSizeMake(75, 21);
[logoLayout addSubview:logoImageView];
// 我的课程按钮
MyLinearLayout *myCourseLayout = [MyLinearLayout linearLayoutWithOrientation:MyOrientation_Horz];
myCourseLayout.gravity = MyGravity_Vert_Center;
myCourseLayout.mySize = CGSizeMake(MyLayoutSize.wrap, MyLayoutSize.wrap);
UILabel *myCourseLabel = [UILabel new];
myCourseLabel.text = @"我的课程";
myCourseLabel.font = [UIFont pingFangSCRegularFontOfSize:14];
myCourseLabel.textColor = [UIColor lk_colorWithHexString:@"#333333"];
myCourseLabel.mySize = CGSizeMake(MyLayoutSize.wrap, MyLayoutSize.wrap);
UIImageView *myCourseArrowImageView = [UIImageView new];
myCourseArrowImageView.image = [[UIImage lk_imageNamed:@"sport_tab_main_right_arrow_icon" inBundleClass:self.class subBundleName:@"LKSportTabMain"] imageByTintColor:[UIColor lk_colorWithHexString:@"#BBBBBB"]];
myCourseArrowImageView.myLeft = 0;
myCourseArrowImageView.mySize = CGSizeMake(MyLayoutSize.wrap, MyLayoutSize.wrap);
[myCourseLayout addSubview:myCourseLabel];
[myCourseLayout addSubview:myCourseArrowImageView];
[myCourseLayout addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onTapCourseHistory:)]];
[logoLayout addSubview:myCourseLayout];
[sportCalendaLayout addSubview:logoLayout];
// 日期菜单
_dateCourseMenu = [LKDateCourseMenu new];
_dateCourseMenu.delegate = self;
_dateCourseMenu.showBottomLine = NO;
_dateCourseMenu.myHorzMargin = 0;
NSString *deviceType = [UIDevice currentDevice].model;
if ([deviceType isEqualToString:@"iPad"]) {
_dateCourseMenu.myHeight = 57 * LKPoint();
} else {
_dateCourseMenu.myHeight = 58;
}
[sportCalendaLayout addSubview:_dateCourseMenu];
// 行程布局
_calendarLayout = [MyLinearLayout linearLayoutWithOrientation:MyOrientation_Horz];
_calendarLayout.myHorzMargin = 0;
_calendarLayout.heightSize.equalTo(@(128));
_calendarLayout.myTop = 12;
[sportCalendaLayout addSubview:_calendarLayout];
// 行程列表
_pageContentView = [[LKPageContentView alloc] init];
_pageContentView.delegate = self;
_pageContentView.mySize = CGSizeMake(MyLayoutSize.fill, MyLayoutSize.fill);
[_calendarLayout addSubview:_pageContentView];
/// 自律空间
MyLinearLayout *disciplineSpaceLayout = [MyLinearLayout linearLayoutWithOrientation:MyOrientation_Vert];
disciplineSpaceLayout.myHorzMargin = 0;
disciplineSpaceLayout.myHeight = MyLayoutSize.wrap;
disciplineSpaceLayout.myTop = 20;
disciplineSpaceLayout.gravity = MyGravity_Horz_Stretch;
_disciplineSpaceLayout = disciplineSpaceLayout;
[contentLayout addSubview:disciplineSpaceLayout];
UILabel *disciplineSpaceLabel = [UILabel new];
disciplineSpaceLabel.text = @"自律空间";
disciplineSpaceLabel.font = [UIFont pingFangSCMediumFontOfSize:20];
disciplineSpaceLabel.textColor = [UIColor lk_colorWithHexString:@"#333333"];
disciplineSpaceLabel.mySize = CGSizeMake(MyLayoutSize.wrap, 20);
[disciplineSpaceLayout addSubview:disciplineSpaceLabel];
// banner
MyRelativeLayout *bannerLayout = [MyRelativeLayout new];
CGFloat width = kScreenWidth - 16 * 2;
bannerLayout.mySize = CGSizeMake(width, width / 335.0 * 100.0);
bannerLayout.myTop = 12;
bannerLayout.visibility = MyVisibility_Gone;
_bannerLayout = bannerLayout;
[disciplineSpaceLayout addSubview:bannerLayout];
LKPagerView *pagerView = [LKPagerView new];
pagerView.interitemSpacing = 18;
pagerView.delegate = self;
pagerView.dataSource = self;
pagerView.automaticSlidingInterval = 3.5;
pagerView.isInfinite = YES;
pagerView.removesInfiniteLoopForSingleItem = YES;
[pagerView registerClass:LKPagerViewCell.class forCellWithReuseIdentifier:NSStringFromClass(LKPagerViewCell.class)];
_banner = pagerView;
pagerView.widthSize.equalTo(bannerLayout.widthSize);
pagerView.heightSize.equalTo(bannerLayout.heightSize);
[bannerLayout addSubview:pagerView];
LKPageControl *pageControl = [LKPageControl new];
pageControl.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter;
[pageControl setItemSpacing:10 forState:UIControlStateNormal];
[pageControl setItemSpacing:18 forState:UIControlStateSelected];
pageControl.interitemSpacing = 3;
pageControl.hidesForSinglePage = YES;
[pageControl setStrokeColor:[UIColor lk_colorWithHexString:@"#FFFFFF"] forState:UIControlStateNormal];
[pageControl setFillColor:[UIColor lk_colorWithHexString:@"#FFFFFF"] forState:UIControlStateNormal];
[pageControl setStrokeColor:[UIColor lk_colorWithHexString:@"#FFFFFF"] forState:UIControlStateSelected];
[pageControl setFillColor:[UIColor lk_colorWithHexString:@"#FFFFFF"] forState:UIControlStateSelected];
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, (10 - 2) / 2.0, 10, 2) cornerRadius:2];
[pageControl setPath:path forState:UIControlStateNormal];
UIBezierPath *path1 = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, (18 - 2) / 2.0, 18, 2) cornerRadius:2];;
[pageControl setPath:path1 forState:UIControlStateSelected];
_pageControl = pageControl;
pageControl.widthSize.equalTo(bannerLayout.widthSize);
pageControl.heightSize.equalTo(@2);
pageControl.bottomPos.equalTo(bannerLayout.bottomPos).offset(7);
[bannerLayout addSubview:pageControl];
/// 领取乐币,饮食打卡,健身赚现金,走跑赢勋章
MyFlowLayout *disciplineSpaceContentLayout = [MyFlowLayout flowLayoutWithOrientation:MyOrientation_Vert arrangedCount:2];
disciplineSpaceContentLayout.myHeight = MyLayoutSize.wrap;
disciplineSpaceContentLayout.gravity = MyGravity_Horz_Fill; //所有子视图水平填充,也就是所有子视图的宽度相等。
disciplineSpaceContentLayout.padding = UIEdgeInsetsMake(14, 0, 16, 0);
disciplineSpaceContentLayout.subviewHSpace = 12;
disciplineSpaceContentLayout.subviewVSpace = 12;
_disciplineSpaceContentLayout = disciplineSpaceContentLayout;
[disciplineSpaceLayout addSubview:disciplineSpaceContentLayout];
}
```