奇怪的 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 来进行调试
似乎也没有太多的信息给出来。
最后无奈搜索相关信息看到了 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 结果也不一样。
真是一个谜。