【问题标题】:UIResponder doesNotRecognizeSelectorUIResponder doesNotRecognizeSelector
【发布时间】:2019-10-16 08:14:58
【问题描述】:

由于以下回溯,我遇到了很多崩溃,但我找不到原因。

根据 Apple -[NSObject(NSObject) doesNotRecognizeSelector:],当一个新对象被分配到之前被释放对象占用的内存中时发生。

注意: 向以前释放的对象发送消息可能会引发 NSInvalidArgumentException 而不是用 内存访问冲突。这发生在分配新对象时 之前被释放对象占用的内存。如果你的 由于未捕获的 NSInvalidArgumentException,应用程序正在崩溃 (寻找 -[NSObject(NSObject) doesNotRecognizeSelector:] 在 异常回溯),请考虑使用 僵尸仪消除记忆不当的可能 管理是原因。

https://developer.apple.com/library/archive/technotes/tn2151/_index.html

但是其余的回溯是怎么回事,尤其是 -[UIUndoGestureInteraction didMoveToView:] 的事情?

Exception Type:  EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Exception Note:  EXC_CORPSE_NOTIFY
Triggered by Thread:  0

Last Exception Backtrace:
0   CoreFoundation                  0x1ae45498c __exceptionPreprocess + 220 (NSException.m:199)
1   libobjc.A.dylib                 0x1ae17d0a4 objc_exception_throw + 56 (objc-exception.mm:565)
2   CoreFoundation                  0x1ae35843c -[NSObject(NSObject) doesNotRecognizeSelector:] + 140 (NSObject.m:144)
3   UIKitCore                       0x1b24902a8 -[UIResponder doesNotRecognizeSelector:] + 296 (UIResponder.m:659)
4   CoreFoundation                  0x1ae458e08 ___forwarding___ + 1324 (NSForwarding.m:3325)
5   CoreFoundation                  0x1ae45abec _CF_forwarding_prep_0 + 92
6   UIKitCore                       0x1b2353040 -[UIUndoGestureInteraction didMoveToView:] + 108 (UIUndoGestureInteraction.m:725)
7   UIKitCore                       0x1b28eb3c4 _setInteractionView + 84 (UIView.m:16421)
8   UIKitCore                       0x1b28eb2a0 -[UIView(Dragging) addInteraction:] + 268 (UIView.m:16450)
9   UIKitCore                       0x1b26cd2b8 -[UIEditingOverlayViewController _addInteractions] + 260 (UIEditingOverlayViewController.m:79)
10  UIKitCore                       0x1b1e5b2ec -[UIViewController _setViewAppearState:isAnimating:] + 832 (UIViewController.m:4695)
11  UIKitCore                       0x1b1e5b6fc __52-[UIViewController _setViewAppearState:isAnimating:]_block_invoke + 268 (UIViewController.m:4758)
12  CoreFoundation                  0x1ae42773c __NSARRAY_IS_CALLING_OUT_TO_A_BLOCK__ + 16 (NSArrayHelpers.m:9)
13  CoreFoundation                  0x1ae32b86c -[__NSArrayI enumerateObjectsWithOptions:usingBlock:] + 152 (NSArrayI.m:108)
14  UIKitCore                       0x1b1e5b49c -[UIViewController _setViewAppearState:isAnimating:] + 1264 (UIViewController.m:4736)
15  UIKitCore                       0x1b1e5d530 __64-[UIViewController viewDidMoveToWindow:shouldAppearOrDisappear:]_block_invoke + 44 (UIViewController.m:5272)
16  UIKitCore                       0x1b1e5c32c -[UIViewController _executeAfterAppearanceBlock] + 88 (UIViewController.m:5050)
17  UIKitCore                       0x1b246bca4 _runAfterCACommitDeferredBlocks + 584 (UIApplication.m:3027)
18  UIKitCore                       0x1b245b7c0 _cleanUpAfterCAFlushAndRunDeferredBlocks + 232 (UIApplication.m:2986)
19  UIKitCore                       0x1b248b594 _afterCACommitHandler + 76 (UIApplication.m:3048)
20  CoreFoundation                  0x1ae3d1c48 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 32 (CFRunLoop.c:1758)
21  CoreFoundation                  0x1ae3ccb34 __CFRunLoopDoObservers + 416 (CFRunLoop.c:1868)
22  CoreFoundation                  0x1ae3cd100 __CFRunLoopRun + 1308 (CFRunLoop.c:2910)
23  CoreFoundation                  0x1ae3cc8bc CFRunLoopRunSpecific + 464 (CFRunLoop.c:3192)
24  GraphicsServices                0x1b8238328 GSEventRunModal + 104 (GSEvent.c:2246)
25  UIKitCore                       0x1b24626d4 UIApplicationMain + 1936 (UIApplication.m:4753)
26  JustConnect                     0x10425ca60 main + 68 (APIInfoUser.swift:7)
27  libdyld.dylib                   0x1ae257460 start + 4

【问题讨论】:

  • 添加异常断点并查看代码中的哪一行出现异常。
  • @PGDev 我似乎无法在调试时重现崩溃。这些是来自 AppStore 的崩溃报告。

标签: ios swift crash backtrace


【解决方案1】:

以下是 Apple 开发人员和技术支持的回复:

这里要注意的关键是此帧的第 0 到第 5 帧 回溯只是与无法识别的样板相关联 选择器。也就是说,第 6 帧调用了一个对象的方法,即 对象无法识别该选择器,因此它进入了 Objective-C 运行时转发基础设施(帧 5 到 4)。那降落 在 UIResponder (第 3 帧)中,因为 UIResponder 支持某种 通用消息转发。该消息转发失败,所以 UIResponder 调用了 super(第 2 帧),然后抛出了异常。

所以真正的问题是,第 6 帧发生了什么。要了解更多信息 关于这个,你可以反汇编代码(-:

(lldb) disas -n '-[UIUndoGestureInteraction didMoveToView:]'  
UIKitCore`-[UIUndoGestureInteraction didMoveToView:]:  
    0x1bbe92fd4 <+0>:   stp    x22, x21, [sp, #-0x30]!  
    0x1bbe92fd8 <+4>:   stp    x20, x19, [sp, #0x10]  
    0x1bbe92fdc <+8>:   stp    x29, x30, [sp, #0x20]  
    0x1bbe92fe0 <+12>:  add    x29, sp, #0x20    ; =0x20   
    0x1bbe92fe4 <+16>:  mov    x21, x2  
    0x1bbe92fe8 <+20>:  mov    x19, x0  
    0x1bbe92fec <+24>:  add    x20, x0, #0x10    ; =0x10   
    0x1bbe92ff0 <+28>:  mov    x0, x20  
    0x1bbe92ff4 <+32>:  mov    x1, x2  
    0x1bbe92ff8 <+36>:  bl     0x1b7cd71d8       ; objc_storeWeak  
    0x1bbe92ffc <+40>:  cbz    x21, 0x1bbe930a8  ; <+212>  
    0x1bbe93000 <+44>:  adrp   x8, 208464  
    0x1bbe93004 <+48>:  add    x1, x8, #0x7b1    ; =0x7b1   
    0x1bbe93008 <+52>:  mov    x0, x19  
    0x1bbe9300c <+56>:  bl     0x1b7cb9180       ; objc_msgSend  
    0x1bbe93010 <+60>:  mov    x0, x20  
    0x1bbe93014 <+64>:  bl     0x1b7cd7a80       ; objc_loadWeakRetained  
    0x1bbe93018 <+68>:  mov    x20, x0  
    0x1bbe9301c <+72>:  adrp   x8, 208304  
    0x1bbe93020 <+76>:  add    x1, x8, #0xc04    ; =0xc04   
    0x1bbe93024 <+80>:  bl     0x1b7cb9180       ; objc_msgSend  
    0x1bbe93028 <+84>:  mov    x29, x29  
    0x1bbe9302c <+88>:  bl     0x1b7cd8864       ; objc_retainAutoreleasedReturnValue  
    0x1bbe93030 <+92>:  mov    x21, x0  
    0x1bbe93034 <+96>:  adrp   x8, 208502  
    0x1bbe93038 <+100>: add    x1, x8, #0xbb7    ; =0xbb7   
    0x1bbe9303c <+104>: bl     0x1b7cb9180       ; objc_msgSend  
    0x1bbe93040 <+108>: stp    d0, d1, [x19, #0x100]  

你可以在这里学到很多东西。首先,第 6 帧 backtrace 的偏移量为 +108,因此失败的实际调用位于 +104。一个 objc_msgSend,有两个标准参数,目标对象和选择器。在 64 位 Arm 上,这些分别映射到 x0 和 x1。

让我们先看看选择器。这是由两者构建的 +96 和 +100 的说明。这两个指令形成一个 PC 相对地址。 adrp 指令(“相对于页面添加”) 获取当前 PC (0x1bbe93034),清除底部 12 位 (0x1bbe93000,记住历史页面大小是4096 [1]),和 然后获取文字,将其左移 12 位(208502

如果您在调试器中运行此计算,您将看到:

(lldb) p (char*)( 0x1bbe93000+(208502<<12)+0xbb7)  
(char *) $1 = 0x00000001eed09bb7 "actualSceneBounds" 

所以选择器是actualSceneBounds。很酷。

现在让我们看看对象。在通话 (+104) 时,这是 预计在 x0 中。在 +92 处,我们看到它将 x0 复制到 x21,但这是 只是分心。实际上 x0 是函数结果 objc_retainAutoreleasedReturnValue 在 +88。该功能需要和 返回一个对象,因此 x0 是发送的消息返回的值 +80。执行与之前相同的相对页面技巧,我们看到该调用的选择器是 -window。但是那个存在是什么对象 调用了吗?

解决这个问题……嗯……有点复杂,因为 objc_storeWeak /objc_loadWeakRetained 舞蹈。我相信它归结为价值 通过x2,也就是第三个参数传入这个方法。基于 在方法名称上,这显然是一个视图(请记住,对于 Objective-C 方法中,前两个参数 x0 和 x1 保存 目标和选择器,所以 x2 保存第一个实际参数)。

所以,总结一下:

  • 好像这个方法有view参数。

  • 请求的是window.window.screenBounds。

  • 最后一次属性访问失败,因为本来是窗口的东西没有实现 -screenBounds getter。

我对 UIKit 的了解不够,无法解释其背景。一世 在这里有几个建议:

  1. 运行标准内存调试工具,特别是 Zombies,看看它们是否发现了任何有用的东西。确保锻炼 撤消手势,基于我们分离的方法的类名。

  2. 如果没有成功,请跳转到 App Frameworks > Cocoa Touch,看看是否有人有任何建议。

分享和享受

[1] 在 64 位 Arm 上,实际页面大小通常为 64 KiB,但 adrp 指令使用 4096 的历史页面大小,因为它 匹配添加指令中的最大文字大小。

https://forums.developer.apple.com/message/389467

【讨论】:

  • 从 iOS 13 开始我也遇到了同样的问题。你找到原因了吗?就我而言,我遇到了 UITabbarController 选择器的问题
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-24
  • 2011-03-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多