ios - 为什么我可以将消息发送到已释放的 NSArray 实例?

标签 ios memory-management nsmutablearray nsarray

我刚刚注意到 NSArray 的一个令人惊讶的行为,这就是我发布这个问题的原因。

我刚刚添加了一个方法,如:

- (IBAction) crashOrNot
{
   NSArray *array = [[NSArray alloc] init];
   array = [[NSArray alloc] init];
   [array release];
   [array release];
}

理论上这段代码会崩溃。但就我而言,它从未崩溃过!!!

我将 NSArray 更改为 NSMutableArray 但这次应用程序崩溃了。 为什么会发生这种情况,为什么 NSArray 不会崩溃而 NSMutableArray 会崩溃?

最佳答案

一般来说,当你释放一个对象时,内存不会被清零,它只是可以被任何需要它的人免费回收。因此,如果您保留指向已释放对象的指针,您通常仍可以使用该对象一段时间(就像您对第二条 -release 消息所做的那样)。示例代码:

#import <Foundation/Foundation.h>

@interface Foo : NSObject
@property(assign) NSUInteger canary;
@end

@implementation Foo
@synthesize canary;
@end

int main(int argc, const char * argv[])
{
    @autoreleasepool {
        Foo *foo = [[Foo alloc] init];
        [foo setCanary:42];
        [foo release];
        NSLog(@"%li", [foo canary]); // 42, no problem
    }
    return 0;
}

默认情况下没有对此进行检查,行为只是未定义。如果您设置了 NSZombieEnabled 环境值,消息传递代码将开始检查已释放的对象,并且应该在您的情况下抛出异常,正如您可能期望的那样:

*** -[Foo canary]: message sent to deallocated instance 0x100108250

顺便说一下,默认的、未检查的情况是内存错误很难调试的原因之一,因为行为可能是高度不确定的(它取决于内存使用模式)。您可能会在代码周围到处出现奇怪的错误,而该错误是其他地方过度发布的对象。继续前面的例子:

Foo *foo = [[Foo alloc] init];
[foo setCanary:42];
[foo release];
Foo *bar = [[Foo alloc] init];
[bar setCanary:11];
NSLog(@"%li", [foo canary]); // 11, magic! (Not guaranteed.)

至于为什么 NSArrayNSMutableArray 不同,一个空数组看起来确实像一个特殊的野兽:

NSArray *foo = [[NSArray alloc] init];
NSArray *bar = [[NSArray alloc] init];
NSLog(@"%i", foo == bar); // yes, they point to the same object

所以这可能与它有关。但在一般情况下,使用已释放的对象可能会做任何事情。它可能有效,也可能无效,它可能会洒出你的咖啡或引发核 war 。不要这样做。

关于ios - 为什么我可以将消息发送到已释放的 NSArray 实例?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13233853/

相关文章:

ios - 解析检索指针对象

android - 用于制作移动应用程序界面草图的工具

c - 通过卡住整个对象来释放链表节点

ios - 无法排序我的NSMutablearray

iphone - 从iphone sdk中的uiwebview下载文件

ios - 如何在 TableView Cell 上使用 iOSCharts (https ://github. com/danielgindi/Charts)?

iphone - 正确从 View 和数组中删除对象?

c++ - 在我的新游戏中找不到内存泄漏?

swift - 快速替换 NSMutableArray 中的值的问题

ios - 一般异常 : Collection was mutated while being enumerated