前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >一个iOS11上的列表必现crash

一个iOS11上的列表必现crash

原创
作者头像
晨之阴影
发布2022-12-01 10:45:00
1K0
发布2022-12-01 10:45:00
举报
文章被收录于专栏:晨光的Code晨光的Code

一个只在iOS11上才发生的crash,crash日志在附件。经过排查后发现是在引导关注弹幕出现的时候退出才会必现crash,之后进行了复现,拿到了完整的crash堆栈。

代码语言:objective-c
复制
    * thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
    frame #0: 0x000000011715398b libobjc.A.dylib`objc_msgSend + 11
    frame #1: 0x000000010dbcd0b9 Foundation`+[NSLayoutConstraint _findCommonAncestorOfItem:andItem:] + 140
    frame #2: 0x000000010ddd2f39 Foundation`NSLayoutConstraintIsDanglyInContainer + 134
    frame #3: 0x000000011199e6b7 UIKit`_UIViewRemoveConstraintsMadeDanglyByChangingSuperview + 1041
    frame #4: 0x0000000110ee205a UIKit`__45-[UIView(Hierarchy) _postMovedFromSuperview:]_block_invoke + 61
    frame #5: 0x0000000110ee1f8a UIKit`-[UIView(Hierarchy) _postMovedFromSuperview:] + 808
    frame #6: 0x0000000110edfe3e UIKit`__UIViewWasRemovedFromSuperview + 169
    frame #7: 0x0000000110edf930 UIKit`-[UIView(Hierarchy) removeFromSuperview] + 479
    frame #8: 0x0000000110ec8c07 UIKit`-[UIView dealloc] + 508
    frame #9: 0x000000011157bcaf UIKit`-[UITableViewCellContentView dealloc] + 68
    frame #10: 0x000000011126c308 UIKit`-[UITableViewCell .cxx_destruct] + 706
    frame #11: 0x000000011713b920 libobjc.A.dylib`object_cxxDestructFromClass(objc_object*, objc_class*) + 127
    frame #12: 0x0000000117147502 libobjc.A.dylib`objc_destructInstance + 124
    frame #13: 0x0000000117147539 libobjc.A.dylib`object_dispose + 22
    frame #14: 0x00000001110575c6 UIKit`-[UIResponder dealloc] + 145
    frame #15: 0x0000000110ec8e04 UIKit`-[UIView dealloc] + 1017
    frame #16: 0x0000000111259800 UIKit`-[UITableViewCell dealloc] + 316
    frame #17: 0x000000010c69246d CoreFoundation`-[__NSArrayM dealloc] + 157
    frame #18: 0x0000000117151a6e libobjc.A.dylib`objc_object::sidetable_release(bool) + 202
    frame #19: 0x0000000110f97482 UIKit`-[UITableView .cxx_destruct] + 1561
    frame #20: 0x000000011713b920 libobjc.A.dylib`object_cxxDestructFromClass(objc_object*, objc_class*) + 127
    frame #21: 0x0000000117147502 libobjc.A.dylib`objc_destructInstance + 124
    frame #22: 0x0000000117147539 libobjc.A.dylib`object_dispose + 22
    frame #23: 0x00000001110575c6 UIKit`-[UIResponder dealloc] + 145
    frame #24: 0x0000000110ec8e04 UIKit`-[UIView dealloc] + 1017
    frame #25: 0x0000000110f039c7 UIKit`-[UIScrollView dealloc] + 816
    frame #26: 0x0000000110f5d990 UIKit`-[UITableView dealloc] + 473
    frame #27: 0x00000001050d64b0 QGame`-[DMKPanel .cxx_destruct](self=0x00007fb4624890a0, _cmd=<no value available>) at DMKPanel.m:53:17
    frame #28: 0x000000011713b920 libobjc.A.dylib`object_cxxDestructFromClass(objc_object*, objc_class*) + 127
    frame #29: 0x0000000117147502 libobjc.A.dylib`objc_destructInstance + 124
    frame #30: 0x0000000117147539 libobjc.A.dylib`object_dispose + 22
    frame #31: 0x00000001110575c6 UIKit`-[UIResponder dealloc] + 145
    frame #32: 0x0000000110ec8e04 UIKit`-[UIView dealloc] + 1017
    frame #33: 0x00000001171521b2 libobjc.A.dylib`(anonymous namespace)::AutoreleasePoolPage::pop(void*) + 860
    frame #34: 0x0000000110ec8de3 UIKit`-[UIView dealloc] + 984
    frame #35: 0x0000000107455a62 QGame`-[QGPortraitFullDanmakuController .cxx_destruct](self=0x00006080006bce60, _cmd=<no value available>) at QGPortraitFullDanmakuController.m:47:17
    frame #36: 0x000000011713b920 libobjc.A.dylib`object_cxxDestructFromClass(objc_object*, objc_class*) + 127
    frame #37: 0x0000000117147502 libobjc.A.dylib`objc_destructInstance + 124
    frame #38: 0x0000000117147539 libobjc.A.dylib`object_dispose + 22
    frame #39: 0x0000000107451ec5 QGame`-[QGPortraitFullDanmakuController dealloc](self=0x00006080006bce60, _cmd="dealloc") at QGPortraitFullDanmakuController.m:107:1
    frame #40: 0x0000000117151a6e libobjc.A.dylib`objc_object::sidetable_release(bool) + 202
    frame #41: 0x000000010c69246d CoreFoundation`-[__NSArrayM dealloc] + 157
    frame #42: 0x0000000117151a6e libobjc.A.dylib`objc_object::sidetable_release(bool) + 202
    frame #43: 0x0000000105135e5e QGame`-[QGSafeMutableArray .cxx_destruct](self=0x000060c000a20880, _cmd=".cxx_destruct") at QGSafeMutableArray.m:31:17
    frame #44: 0x000000011713b920 libobjc.A.dylib`object_cxxDestructFromClass(objc_object*, objc_class*) + 127
    frame #45: 0x0000000117147502 libobjc.A.dylib`objc_destructInstance + 124
    frame #46: 0x0000000117147539 libobjc.A.dylib`object_dispose + 22
    frame #47: 0x0000000117151a6e libobjc.A.dylib`objc_object::sidetable_release(bool) + 202
    frame #48: 0x0000000106ab01f2 QGame`-[QGLiveDetailCommunicationCenter removeBusinessControllers:](self=0x00006040008254a0, _cmd="removeBusinessControllers:", businessControllers=0x0000604000a21c20) at QGLiveDetailCommunicationCenter.m:61:1
    frame #49: 0x0000000106ab02f2 QGame`-[QGLiveDetailCommunicationCenter cleanBusinessControllers](self=0x00006040008254a0, _cmd="cleanBusinessControllers") at QGLiveDetailCommunicationCenter.m:64:5
    frame #50: 0x00000001067db04a QGame`-[QGVoiceRoomViewController dealloc](self=0x00007fb4623f68c0, _cmd="dealloc") at QGVoiceRoomViewController.m:111:5
    frame #51: 0x0000000106488128 QGame`-[QGLiveVCContainer .cxx_destruct](self=0x00007fb4623dc910, _cmd=".cxx_destruct") at QGLiveVCContainer.m:36:17
    frame #52: 0x000000011713b920 libobjc.A.dylib`object_cxxDestructFromClass(objc_object*, objc_class*) + 127
    frame #53: 0x0000000117147502 libobjc.A.dylib`objc_destructInstance + 124
    frame #54: 0x0000000117147539 libobjc.A.dylib`object_dispose + 22
    frame #55: 0x00000001110575c6 UIKit`-[UIResponder dealloc] + 145
    frame #56: 0x0000000110fca8f2 UIKit`-[UIViewController dealloc] + 1807
    frame #57: 0x0000000106f6550d QGame`-[UIViewController(self=0x00007fb4623dc910, _cmd="dealloc") grayUpgradeAlert] at UIViewController+GrayUpgrade.m:128:5
    frame #58: 0x00000001068d4ad5 QGame`-[QGViewController dealloc](self=0x00007fb4623dc910, _cmd="dealloc") at QGViewController.m:231:1
    frame #59: 0x00000001064851df QGame`-[QGLiveVCContainer dealloc](self=0x00007fb4623dc910, _cmd="dealloc") at QGLiveVCContainer.m:119:1
    frame #60: 0x0000000111001252 UIKit`__destroy_helper_block_.859 + 38
    frame #61: 0x0000000118c6398a libsystem_blocks.dylib`_Block_release + 111
    frame #62: 0x0000000111b83fe9 UIKit`-[_UIViewControllerTransitionContext .cxx_destruct] + 94
    frame #63: 0x000000011713b920 libobjc.A.dylib`object_cxxDestructFromClass(objc_object*, objc_class*) + 127
    frame #64: 0x0000000117147502 libobjc.A.dylib`objc_destructInstance + 124
    frame #65: 0x0000000117147539 libobjc.A.dylib`object_dispose + 22
    frame #66: 0x0000000111b8282e UIKit`-[_UIViewControllerTransitionContext dealloc] + 55
    frame #67: 0x0000000111b8408e UIKit`-[_UIViewControllerOneToOneTransitionContext dealloc] + 78
    frame #68: 0x0000000117151a6e libobjc.A.dylib`objc_object::sidetable_release(bool) + 202
    frame #69: 0x0000000105096e9d QGame`__destroy_helper_block_e8_32s((null)=0x000060800024fd80) at DMKAchievementMedalMaterialGen.m:39:28
    frame #70: 0x0000000118c6398a libsystem_blocks.dylib`_Block_release + 111
    frame #71: 0x0000000110eec1e5 UIKit`-[UIViewAnimationBlockDelegate .cxx_destruct] + 58
    frame #72: 0x000000011713b920 libobjc.A.dylib`object_cxxDestructFromClass(objc_object*, objc_class*) + 127
    frame #73: 0x0000000117147502 libobjc.A.dylib`objc_destructInstance + 124
    frame #74: 0x0000000117147539 libobjc.A.dylib`object_dispose + 22
    frame #75: 0x0000000117151a6e libobjc.A.dylib`objc_object::sidetable_release(bool) + 202
    frame #76: 0x000000010c6c364d CoreFoundation`-[__NSDictionaryI dealloc] + 125
    frame #77: 0x0000000117151a6e libobjc.A.dylib`objc_object::sidetable_release(bool) + 202
    frame #78: 0x00000001171521b2 libobjc.A.dylib`(anonymous namespace)::AutoreleasePoolPage::pop(void*) + 860
    frame #79: 0x000000010c6aa136 CoreFoundation`_CFAutoreleasePoolPop + 22
    frame #80: 0x000000010c6e6eae CoreFoundation`__CFRunLoopRun + 2350
    frame #81: 0x000000010c6e630b CoreFoundation`CFRunLoopRunSpecific + 635
    frame #82: 0x0000000119959a73 GraphicsServices`GSEventRunModal + 62
    frame #83: 0x0000000110e2a057 UIKit`UIApplicationMain + 159
    frame #84: 0x0000000106c38b84 QGame`main(argc=1, argv=0x00007ffeeab6a3d8) at main.m:46:16
    frame #85: 0x0000000118bf2955 libdyld.dylib`start + 1
    frame #86: 0x0000000118bf2955 libdyld.dylib`start + 1

如堆栈所示,crash发生在弹幕面板dealloc的时候,当UITableView进行dealloc时,会对所有的cell进行dealloc,cell的subview会执行removeFromSuperView方法,最后crash在[NSLayoutConstraint _findCommonAncestorOfItem:andItem:],从方法名上可以看到应该是因为某两个subview的约束出现了问题,这两个item有一个commonAncestor导致了crash,虽然不太明确为什么iOS11上两个subview有commonAncestor时dealloc会crash,但检查代码和当版本需求后确认是DMKLocalFocusDanmuCell引入的。

首先描述下引导关注弹幕的特殊逻辑,需求要求首先在弹幕面板上方展示引导关注按钮,可以有正常关注逻辑,之后展示3秒后,引导关注按钮转为一条特殊弹幕,同样有正常关注逻辑,并且即使此弹幕划走之后,关注状态依然会有通知进行相应。因此为了达到逻辑复用和对弹幕面板侵入性最少,选择了新建DanmuCell并在config时将引导关注View贴在弹幕cell上,但同时UITableView中的cell是会回收的,为了保证关注view能响应通知,因此使用了model层来持有了这个view,也为之后的crash埋下了隐患。

修复方案,在danmuCell的dealloc方法里手动讲引导关注按钮removeFromSuperView,并将danmuCell中的指针置为nil,这样保证了cell在dealloc时不再需要处理引导关注按钮。

代码语言:objective-c
复制
- (void)configureWithLayout:(DMKItemLayout *)layout {
    [super configureWithLayout:layout];
    if (layout.focusDanmuView == nil) {
        [layout configFocusView];
        
    }
    [self.focusDanmuView removeFromSuperview];
    [layout.focusDanmuView removeFromSuperview];
    self.focusDanmuView = layout.focusDanmuView;
    [self.contentView removeAllSubviews];
    [self.contentView addSubview:self.focusDanmuView];
    [self.focusDanmuView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.centerY.equalTo(self.focusDanmuView.superview);
        make.left.equalTo(self.focusDanmuView.superview).offset(10);
    }];
}
// iOS 11必须手动移除subview 不然会crash
- (void)dealloc {
    [self.focusDanmuView removeFromSuperview];
    self.focusDanmuView = nil;
}

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
移动应用安全
移动应用安全(Mobile Application Security,MS)针对移动应用普遍存在的破解、篡改、重打包等各类安全风险,提供Android应用加固、iOS源码混淆、SDK加固等多种加固技术,拥有丰富的行业经验,已服务于金融、互联网、车联网、物联网,运营商等多个行业。稳定、简单、有效,让移动安全建设不再是一种负担。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档