Contents
  1. 1. 奇怪的 objc_msgSend crash
  2. 2. 访问 UICollectionViewController 的 collectionView 引发 SIGSGV

奇怪的 objc_msgSend crash

在项目中遇到了一些只在 iOS 8 中发生的 crash,特征是出现在主线程中且多余的信息没有只有一个.

objc_msgSend() selector name: respondsToSelector:
main.m, line 14
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Thread 0 Crashed:
0 libobjc.A.dylib 0x0000000197f9fbd0 objc_msgSend + 16
1 UIKit 0x000000018b25ab08 -[UINavigationController viewWillAppear:] + 468
2 UIKit 0x000000018b1bff74 -[UIViewController _setViewAppearState:isAnimating:] + 512
3 UIKit 0x000000018b2def08 -[UITabBarController transitionFromViewController:toViewController:transition:shouldSetSelected:] + 608
4 UIKit 0x000000018b2deb58 -[UITabBarController _setSelectedViewController:] + 356
5 UIKit 0x000000018b3a6378 -[UITabBarController _tabBarItemClicked:] + 332
6 UIKit 0x000000018b1dd404 -[UIApplication sendAction:to:from:forEvent:] + 92
7 UIKit 0x000000018b3a61cc -[UITabBar _sendAction:withEvent:] + 464
8 UIKit 0x000000018b1dd404 -[UIApplication sendAction:to:from:forEvent:] + 92
9 UIKit 0x000000018b1c64e0 -[UIControl _sendActionsForEvents:withEvent:] + 608
10 UIKit 0x000000018b3a5e04 -[UITabBar(Static) _buttonUp:] + 124
11 UIKit 0x000000018b1dd404 -[UIApplication sendAction:to:from:forEvent:] + 92
12 UIKit 0x000000018b1c64e0 -[UIControl _sendActionsForEvents:withEvent:] + 608
13 UIKit 0x000000018b1dcda0 -[UIControl touchesEnded:withEvent:] + 588
14 UIKit 0x000000018b19bfc0 _UIGestureRecognizerUpdate + 8532
15 CoreFoundation 0x00000001867202a4 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 28
16 CoreFoundation 0x000000018671d230 __CFRunLoopDoObservers + 356
17 CoreFoundation 0x000000018671d610 __CFRunLoopRun + 832
18 CoreFoundation 0x00000001866492d4 CFRunLoopRunSpecific + 392
19 GraphicsServices 0x000000018fe5f6fc GSEventRunModal + 164
20 UIKit 0x000000018b20efac UIApplicationMain + 1484
21 xiaobandeng 0x0000000100102e38 main (main.m:14)
22 libdyld.dylib 0x000000019860aa08 start + 0

或者这样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Thread 0 Crashed:
0 libobjc.A.dylib 0x000000019479bbdc objc_msgSend + 28
1 UIKit 0x000000018897dbc0 -[UINavigationController viewWillAppear:] + 468
2 UIKit 0x00000001888e3bd4 -[UIViewController _setViewAppearState:isAnimating:] + 512
3 UIKit 0x0000000188a06744 -[UITabBarController viewWillAppear:] + 240
4 UIKit 0x00000001888e3bd4 -[UIViewController _setViewAppearState:isAnimating:] + 512
5 UIKit 0x0000000188bc9120 __56-[UIPresentationController runTransitionForCurrentState]_block_invoke + 704
6 UIKit 0x000000018894eefc _applyBlockToCFArrayCopiedToStack + 352
7 UIKit 0x00000001888c09c0 _afterCACommitHandler + 528
8 CoreFoundation 0x0000000184102388 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 28
9 CoreFoundation 0x00000001840ff314 __CFRunLoopDoObservers + 356
10 CoreFoundation 0x00000001840ff6f4 __CFRunLoopRun + 832
11 CoreFoundation 0x000000018402d664 CFRunLoopRunSpecific + 392
12 GraphicsServices 0x000000018d1675a4 GSEventRunModal + 164
13 UIKit 0x00000001889324f8 UIApplicationMain + 1484
14 xiaobandeng 0x0000000100086e38 main (main.m:14)
15 libdyld.dylib 0x0000000194df6a08 start + 0

或者这样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Thread 0 Crashed:
0 libobjc.A.dylib 0x328b6f66 objc_msgSend + 6
1 UIKit 0x27c5a661 -[UIScrollView(UIScrollViewInternal) _delegateScrollViewAnimationEnded] + 50
2 UIKit 0x27c5a5ed -[UIScrollView(UIScrollViewInternal) _scrollViewAnimationEnded:finished:] + 182
3 UIKit 0x27d0385d -[UIAnimator stopAnimation:] + 474
4 UIKit 0x27d03239 -[UIAnimator(Static) _advanceAnimationsOfType:withTimestamp:] + 302
5 UIKit 0x27d03105 -[UIAnimator(Static) _LCDHeartbeatCallback:] + 50
6 QuartzCore 0x275d1bb7 CA::Display::DisplayLinkItem::dispatch() + 96
7 QuartzCore 0x275d1a1f CA::Display::DisplayLink::dispatch_items(unsigned long long, unsigned long long, unsigned long long) + 364
8 IOMobileFramebuffer 0x2c1a1c03 IOMobileFramebufferVsyncNotifyFunc + 88
9 IOKit 0x254a5d0d IODispatchCalloutFromCFMessage + 254
10 CoreFoundation 0x244e2555 __CFMachPortPerform + 130
11 CoreFoundation 0x244f2a4b __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 32
12 CoreFoundation 0x244f29e7 __CFRunLoopDoSource1 + 344
13 CoreFoundation 0x244f1009 __CFRunLoopRun + 1606
14 CoreFoundation 0x2443c9a1 CFRunLoopRunSpecific + 474
15 CoreFoundation 0x2443c7b3 CFRunLoopRunInMode + 104
16 GraphicsServices 0x2bbec1a9 GSEventRunModal + 134
17 UIKit 0x27bc7695 UIApplicationMain + 1438
18 xiaobandeng 0x001064f5 main (main.m:14)
19 libdyld.dylib 0x32e52aaf start + 0

以及这样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
Thread 0 Crashed:
0 libobjc.A.dylib 0x000000019824bbd0 objc_msgSend + 16
1 UIKit 0x000000018b506b08 -[UINavigationController viewWillAppear:] + 468
2 UIKit 0x000000018b46bf74 -[UIViewController _setViewAppearState:isAnimating:] + 512
3 UIKit 0x000000018b58af08 -[UITabBarController transitionFromViewController:toViewController:transition:shouldSetSelected:] + 608
4 UIKit 0x000000018b58ab58 -[UITabBarController _setSelectedViewController:] + 356
5 UIKit 0x000000018b652378 -[UITabBarController _tabBarItemClicked:] + 332
6 UIKit 0x000000018b489404 -[UIApplication sendAction:to:from:forEvent:] + 92
7 UIKit 0x000000018b6521cc -[UITabBar _sendAction:withEvent:] + 464
8 UIKit 0x000000018b489404 -[UIApplication sendAction:to:from:forEvent:] + 92
9 UIKit 0x000000018b4724e0 -[UIControl _sendActionsForEvents:withEvent:] + 608
10 UIKit 0x000000018b651e04 -[UITabBar(Static) _buttonUp:] + 124
11 UIKit 0x000000018b489404 -[UIApplication sendAction:to:from:forEvent:] + 92
12 UIKit 0x000000018b4724e0 -[UIControl _sendActionsForEvents:withEvent:] + 608
13 UIKit 0x000000018b488da0 -[UIControl touchesEnded:withEvent:] + 588
14 UIKit 0x000000018b488a2c -[UIWindow _sendTouchesForEvent:] + 696
15 UIKit 0x000000018b481f68 -[UIWindow sendEvent:] + 680
16 UIKit 0x000000018b45518c -[UIApplication sendEvent:] + 260
17 UIKit 0x000000018b6f6324 _UIApplicationHandleEventFromQueueEvent + 15420
18 UIKit 0x000000018b4536a0 _UIApplicationHandleEventQueue + 1712
19 CoreFoundation 0x00000001869cc240 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 20
20 CoreFoundation 0x00000001869cb4e4 __CFRunLoopDoSources0 + 260
21 CoreFoundation 0x00000001869c9594 __CFRunLoopRun + 708
22 CoreFoundation 0x00000001868f52d4 CFRunLoopRunSpecific + 392
23 GraphicsServices 0x000000019010b6fc GSEventRunModal + 164
24 UIKit 0x000000018b4bafac UIApplicationMain + 1484
25 xiaobandeng 0x00000001000cae38 main (main.m:14)
26 libdyld.dylib 0x00000001988b6a08 start + 0

无从下手,不知道发生在哪里,不知道发生了什么。能够知道的唯一线索就是这是 iOS 8.x 特有的其他版本都没有,以及这是一个 SIGSEGV 内存错误。似乎是访问了已经 dealloc 的内存。

为了找到问题所在,专门下载 iOS 8 的模拟器开启了 Zoombie 来进行调试

http://wx2.sinaimg.cn/large/005XFMkjly1fhu1mxsjbmj31kw0qb4eg.jpg

似乎也没有太多的信息给出来。

最后无奈搜索相关信息看到了 https://stackoverflow.com/questions/30654062/ios-8-crash-objc-msgsend-selector-name-respondstoselector

最后发现是 NavigationControllerDelegate 的问题。

在 iOS 8.X 中,NavigationController 的 delegate 是被 assign 修饰的,在 iOS 9 中才被改成了 weak。这就意味着 NavigationController 的 delegate 是不会被自动清除,会在特定条件下触发野指针问题也就是这里遇到的问题。同时在 dealloc方法中做清除工作也于事无补。代理方法执行的比dealloc早,要在 viewDidDisappear 中清除 delegate 才行。

这样看来,iOS 8 还存在很多类似这样的问题。

访问 UICollectionViewController 的 collectionView 引发 SIGSGV

这个问题也是只发生在 iOS 8.X 中,具体表现为访问 UICollectionViewController 的 collectionView 就 crash。

crash 报告了在哪个文件哪一行,crash 描述为

1
objc_msgSend() selector name: retain

对 collectionView 发出了 retain 操作,而 collectionView 已经被释放所以导致错误。collectionView 被释放??

还是在 UICollectionViewController 中??

最终发现是在 A VC 中加上了 B VC 的 collectionView

[a.view addSubview:b.collectionView]

然后调用了

[b.collectionView removeFromSuperView]

正是这个 Remove 操作把 collectionView 从父 view 中移除了。当然改成

[a.view addSubview:b.view]

[b.view removeFromSuperView] 就能解决问题。然而,对应的 tableView 却没发生类似的情况呢?

collectionView 明明是被 UICollectionViewController retain 的(iOS 9 改成了 strong 修饰),即使从视图树移除了那 UICollectionViewController 还对它至少有 1 个引用。为什么就对象销毁了呢?。removeFromSuperView中到底做了什么?相同的操作对 tableView 确实正常的,不会产生影响。同时注意到 WrapperView 在 collectionView 和 tableView 之间的细微差别,很有意思。

UICollectionView 被 UICollectionViewControllerWrapperView 包裹着,而 UITableView 包裹着 UITableViewWrapperView。

分别对 tableView 和 collectionView 调 removeFromSuperView 结果也不一样。

真是一个谜。

Contents
  1. 1. 奇怪的 objc_msgSend crash
  2. 2. 访问 UICollectionViewController 的 collectionView 引发 SIGSGV