我刚注意到NSArray
的惊人行为,这就是我发布此问题的原因。
我刚刚添加了一个方法:
- (IBAction) crashOrNot
{
NSArray *array = [[NSArray alloc] init];
array = [[NSArray alloc] init];
[array release];
[array release];
}
理论上这段代码会崩溃。但就我而言,它永远不会崩溃!!!
我使用NSArray
更改了NSMutableArray
,但这次应用程序崩溃了。
为什么会发生这种情况,为什么NSArray
没有崩溃而NSMutableArray
崩溃?
答案 0 :(得分:7)
通常,当您释放一个对象时,内存不会被清零,只需要任何需要它的人就可以自由地回收它。因此,如果保留指向解除分配对象的指针,通常仍可以使用该对象一段时间(就像使用第二个-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.)
至于为什么NSArray
与NSMutableArray
不同,一个空数组看起来确实像一个特殊的野兽:
NSArray *foo = [[NSArray alloc] init];
NSArray *bar = [[NSArray alloc] init];
NSLog(@"%i", foo == bar); // yes, they point to the same object
所以这可能与它有关。但在一般情况下,使用解除分配的对象可能会做任何事情。它可能会起作用,它可能不会,它可能会溢出你的咖啡或开始核战争。不要这样做。
答案 1 :(得分:3)
我能想到的最简单的事情是,基础框架中的空NSArray
是某种“常量” - 例如一个类似于NSString
文字的对象,其中retainCount
(如果你要调用它)为-1,它永远不会是-dealloc
'。