IMP methodForSelector EXC_BAD_ACCESS 崩溃

Posted

技术标签:

【中文标题】IMP methodForSelector EXC_BAD_ACCESS 崩溃【英文标题】:IMP methodForSelector EXC_BAD_ACCESS crash 【发布时间】:2015-02-03 19:10:09 【问题描述】:

我收到了几份崩溃报告,唯一的共同点是它们都是 iPhone 5。我无法在 iPhone 5s 或 6 上重现崩溃,所以我认为它是 64/32位问题。不过,该代码在运行 ios 7 的 iPhone 4s 上也能正常运行。

崩溃发生在此处的最后一行:

IMP imp = [self.delegate methodForSelector:aSelector];
id (*func)(id, SEL, id) = (void *)imp;
func(self.delegate, aSelector, self);

老实说,我不明白这 3 行代码。我发现他们在使用[self.delegate performSelector:aSelector withObject:self]; 时克服了编译器警告may cause a leak because its selector is unknown 当我使用 performSelector 推送更新时,它不会崩溃。

我需要将self 的参数与选择器一起传递,这就是我使用IMP 并添加self 作为第三个参数的原因,这是我应该如何阅读它的原因。

实际的崩溃日志并没有透露太多:

Crashed: com.apple.main-thread EXC_BAD_ACCESS KERN_INVALID_ADDRESS at 0x00000100 Thread : Crashed: com.apple.main-thread 
0  libobjc.A.dylib  0x30ca26b8 objc_retain + 7 
1  Timeout                        0x0009e2a1 __50-[BaseOperation finishedSuccessfullyWithSelector:]_block_invoke_2 (BaseOperation.m:47) 
2  libdispatch.dylib              0x311e87bb
_dispatch_call_block_and_release + 10 
3  libdispatch.dylib              0x311efe8b _dispatch_after_timer_callback + 66 
4  libdispatch.dylib    0x311e87a7 _dispatch_client_callout + 22 
5  libdispatch.dylib          0x311f9253 _dispatch_source_latch_and_call + 626 
6  libdispatch.dylib  0x311ea2ed _dispatch_source_invoke + 212 
7  libdispatch.dylib          0x311ebe1f _dispatch_main_queue_callback_4CF + 330 
8  CoreFoundation   0x234a39d1 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 8 
9  CoreFoundation                 0x234a20d1 __CFRunLoopRun + 1512 
10 CoreFoundation                 0x233f0211 CFRunLoopRunSpecific + 476 
11 CoreFoundation                 0x233f0023 CFRunLoopRunInMode + 106 
12 GraphicsServices               0x2a7e90a9 GSEventRunModal + 136 
13 UIKit                          0x269fc1d1 UIApplicationMain + 1440 
14 Timeout                        0x000a265b main (main.m:14)

有没有人可以解释一下?

谢谢

编辑---- 我现在也看到 iPad 3 (iOS 8.1.2) 和 iPhone 5 (iOS 8.1) 上的崩溃。但是我自己还是无法重现,我还尝试了 iPod (iOS 8.1) 和 iPad mini Retina (iOS 8.1.3)。这真的让我很烦(双关语)。

编辑 2 ---- 我添加了一些 Crashlytics 日志来记录 self.delegate self impfunc,它们看起来都很好!那么为什么下一行会崩溃呢?

0   |   00:01:33:665    |   $ __50-[BaseOperation finishedSuccessfullyWithSelector:]_block_invoke_2 : connectComplete:
1   |   00:01:33:665    |   $ delegate: <BaseMenuViewController: 0x17e5e780>
2   |   00:01:33:666    |   $ self: <ConnectOperation_Virgin: 0x1902a490>name = '(null)'
3   |   00:01:33:667    |   $ imp: 0xaa345
4   |   00:01:33:667    |   $ func: 0xaa345

【问题讨论】:

【参考方案1】:

我遇到了同样的问题,6 个月前的工作代码现在崩溃了,通过这些更改修复了它:

//旧代码

 IMP imp = [_target methodForSelector:_action];
 id (*func)(id, SEL, id) = (void *)imp;
 func(_target, _action, params);

//替换为

 void (*imp)(id, SEL, id) = (void(*)(id,SEL,id))[_target methodForSelector:_action];
 if( imp ) imp(_target, _action, params);

【讨论】:

以上是关于IMP methodForSelector EXC_BAD_ACCESS 崩溃的主要内容,如果未能解决你的问题,请参考以下文章

错误:“线程 1:EXC_BAD_ACCESS(代码=EXC_I386_GPFLT)

线程 1:EXC_BAD_INSTRUCTION(code=EXC_I386_INVOP,subcode=0*0) 错误

线程 1:EXC_BAD_ACCESS(代码=EXC_I386_GPFLT)

错误“线程 1:EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)”是啥意思?

错误 - 线程 1 exc_bad_instruction(代码=exc_1386_invop 子代码=0x0)

斯威夫特 3 - 'EXC_BAD_INSTRUCTION(代码 = EXC_1386_INVOP,子代码 = 0x0)' 错误