我正在尝试对iOS进行调试,该iOS在支持A64指令集的设备上持续再现。特别是使用A7/A8X SOC的iPad。在任何32位iPad上运行时,完全相同的代码也将始终崩溃(如果我将构建仅限于32位体系结构,则适用于相同的情况,然后在一个上运行32位代码64位具有iPad)。
崩溃报告为EXC_BAD_ACCESS
,并且对触发它的代码没有什么特别的幻想:
if (object && [self respondsToSelector:addSelector]) {
objc_msgSend(self, addSelector, object); //EXC_BAD_ACCESS on A64 devices!
//[self performSelector:addSelector withObject:object]; //no crash
}
有问题的行是objc_msgSend(self, addSelector, object);
。第一个令人困惑的部分是,如果我用[self performSelector:addSelector withObject:object];
替换这条线,一切都应该奏效(尽管它使我感到令人讨厌的" PerformSelector可能会导致泄漏..."警告)。除非我完全误解了某些内容,否则在这种情况下,objc_msgSend
和performSelector:withObject:
本质上应等效。
那么,为什么一个一个崩溃(仅在使用A64时)而另一个不使用?
下一个令人困惑的事情是在试图在发生崩溃时调试崩溃时会发生的。self
和object
都是NSManagedObject
实例,我可以在调试器中观察到它们都是有效的对象。但是,该例外总是报告为:
-[NSManagedObjectContext entity]: unrecognized selector sent to instance 0x...
该呼叫显示为源自CoreData
的内部设备,我无法提出任何可能发生的情况的合理解释,尤其是作为切换到32位转换为64--的副作用位体系结构/构建。
有什么想法会导致这种问题?还是我应该选择那个performSelector:withObject:
并开心?
,触发它的代码没有什么特别的幻想
直接调用 objc_msgSend()
是 fancy,并且在发现时正确地做到了。
第一个令人困惑的部分是,如果我用[self performelector:addSelector with obobject:object]; extery exterector
替换此行
是的。因为这些不一样。
objc_msgSend*
有几种口味,您需要根据返回类型和处理器选择正确的口味。具体来说,有三个版本:
-
objc_msgSend_fpret
-对于浮点返回类型(适用于OS X;我没有查找它是否适用于64位臂) -
objc_msgSend_stret
-对于结构返回类型(例如CGPoint
) -
objc_msgSend
-对于其他返回类型
如果在所有处理器上总是始终是 true,我不记得我的头顶。一些处理器对"大"结构的处理方式不同于"小"结构。呼叫约定都是非常特定于处理器的,这就是为什么您只在一个处理器上看到它的原因。还记得我说直接打电话objc_msgSend()
时很喜欢吗?
您正在使用它来调用任意选择器的事实表明,其中一些人具有结构或浮点返回,在这种情况下,事物将在错误的寄存器中,并且事情将完全侧面进行。p>有关此此讨论的更多讨论,请参阅为什么Objective-C编译器需要了解方法签名?
有什么想法会导致这种问题?还是我应该选择那个performelector:withObject:快乐?
正如警告所述,performSelector:
可能会泄漏,因为ARC不知道如何进行内存来管理它。解决方案是对此进行重新处理以使用块而不是选择器。如果您必须使用选择器,并且可以肯定地知道,此处都没有调用返回对象的选择器,请参见https://stackoverflow.com/a/7933931/97337有关如何使警告保持沉默。如果这些可以返回对象,那么您需要确保在它们上不能有额外的保留,这只是您可能不应该下降的兔子洞(或至少应该作为一个新问题提出)。