有意向已释放对象发送消息的 Objective-c 示例代码

Posted

技术标签:

【中文标题】有意向已释放对象发送消息的 Objective-c 示例代码【英文标题】:Objective-c example code that intentionally messages a deallocated object 【发布时间】:2015-08-14 17:55:35 【问题描述】:

我是 objective-cxcode 的新手,我目前正在编写的应用程序收到了臭名昭著的 EXC_BAD_ACCESS 错误。

几乎每个人都建议开始使用 NSZombies 来解决问题。我认为我的 NSZombies 正在运行,但 xcode 并没有提醒我在我的应用崩溃时收到了关于 zombie 的消息。

在继续调试之前,我想运行一些代码,这些代码肯定会导致将消息发送到 zombie(解除分配的对象)。

什么是简单的代码 sn-p,其中消息被发送到已释放的对象,导致 NSZombies 应该提醒我的情况?

【问题讨论】:

@zaph 不,这是内存泄漏。僵尸是指向已释放对象的指针。 @zaph 如果您启用了僵尸,那么在您解除分配对象时会留下僵尸。僵尸不会释放该内存,而是持有该内存,并且可以在向它发送消息时提醒您 - 应该是一个已释放的对象。 @zaph 僵尸(作为调试工具)的全部意义在于找到仍然有指向已释放对象的指针的情况,然后您尝试访问该对象。跨度> @zaph,这个问题是专门询问 NSZombie,在说什么? 好吧,我给出了一个常识,即如果不启用僵尸对象,僵尸就无法存在。这与僵尸任务的概念完全相反,我认为僵尸任务的命名早于僵尸对象。 【参考方案1】:

对于非 ARC 代码:

- (IBAction) messageZombie:(id)sender 
    id a = [[NSObject alloc]init];
    [a release];
    NSLog(@"%@", [a description]);

这将在 Zombies 关闭时为您提供 EXC_BAD_ACCESS,并在 Zombies 启用时为您提供“消息发送到已释放实例”消息。

如果您的项目正在使用 ARC,那么将消息可靠地发送给已释放的对象会有点困难(毕竟,这就是 ARC 的要点)。

这行得通:

- (IBAction) messageZombie:(id)sender     
    id a = [[NSObject alloc]init];
    id __unsafe_unretained b =a;
    a=nil;
    NSLog(@"%@", [b description]);

这可能与您的实际代码所做的不太相似,因为到底谁在使用 __unsafe_unretained?但是如果你只是想确保你已经正确打开了 NSZombies,这应该是一个合理的测试用例。

如果您正在寻找代码中的可疑位置,那么请务必查找 __unsafe_unretained 指针,尽管您不会找到任何*,并仔细检查正确的转换是否用于转换为 Cocoa 的 CoreFoundation 对象对象。

* 如果你的项目需要支持 10.7 之前的 OS X 版本,或者 5.0 之前的 ios 版本,那么你不能使用 __weak 指针,所以在那种项目中,你会发现 __unsafe_unretained 的使用频率更高。

【讨论】:

@MarkBessey 谢谢,这就是我要找的东西,唯一的问题是我启用了自动引用计数并且我收到错误:“ARC 禁止发送'release'的显式消息” 这实际上可能不会崩溃,即使僵尸关闭。 好吧,如果你启用了 ARC,你就不应该有任何僵尸,除非你误用了弱指针。很公平 - 我将为 ARC 代码再举一个例子。 @MarkBessey 可能会误用弱指针,我正在进入一个在开始之前就出现问题的项目。感谢您的帮助。 另外没有提到的是必须启用“启用僵尸对象”选项。另外需要注意的是,使用此设置,每次释放都会泄漏,因为内存不会被回收,完成后删除此设置是必不可少的。【参考方案2】:

您可以创建一个 CF 对象,将其桥接到一个 Objective-C 对象,然后释放它并尝试使用桥接的对象。我认为你必须使用 __bridge 才能让它按照你想要的方式运行。

【讨论】:

以上是关于有意向已释放对象发送消息的 Objective-c 示例代码的主要内容,如果未能解决你的问题,请参考以下文章

一条 Objective-C 消息被发送到地址 0x1 处已释放的“__NSDictionaryI”对象(僵尸)

nil 和释放对象的区别

一条 Objective-C 消息被发送到一个释放的 'UIActivityIndi​​catorView' 对象

发送到已释放实例的消息

如何查找匹配对象:-[CFArray _cfTypeID]:发送到已释放实例的消息

如何保护对象免受自动释放?