为什么未初始化的变量包含垃圾而不是'nil'?

Jar*_*kus 2 memory xcode initialization objective-c

环境:Mac OS X 10.9,Xcode 5.0.2

我为OS X创建标准Cocoa应用程序并在项目设置中禁用ARC.添加一个按钮"运行":

文件"AppDelegate.h":

#import <Cocoa/Cocoa.h>

@interface AppDelegate : NSObject <NSApplicationDelegate>

@property (assign) IBOutlet NSWindow *window;
- (IBAction)clickRun:(id)sender;

@end 
Run Code Online (Sandbox Code Playgroud)

文件"AppDelegate.m":

#import "AppDelegate.h"

@implementation AppDelegate

- (IBAction)clickRun:(id)sender
{  
    NSAutoreleasePool* apool = [[NSAutoreleasePool alloc] init];

    NSString* pathToFile = @"/Users/admin/1.txt";

    NSError* error;

    NSLog(@"[1] Retain count of Error: %lx", [error retainCount]);

    NSData* dataOfFile = [NSData dataWithContentsOfFile:pathToFile
                                                options:NSDataReadingMappedIfSafe
                                                  error:&error];

    NSLog(@"[2] Retain count of Error: %lx", [error retainCount]);

    [apool drain];
}
@end
Run Code Online (Sandbox Code Playgroud)

当运行程序和第一次单击按钮控制台输出时:

" [1]保留错误计数:0 " - 当然为零因为变量'错误'未初始化
" [2]保留错误计数:0 " - 第二个零告诉我们"dataWithContentsOfFile"成功读取文件的方法.

并且调试器始终说出变量'error'键入'nil'.

但是当我第二次单击按钮时,调试器会中断:

NSLog(@"[1]保留错误计数:%lx",[错误retainCount]);

并显示消息"EXC_BAD_ACCESS"和变量'error'包含垃圾,当然[error retainCount]得到分段错误.但这有点奇怪,因为如果方法"dataWithContentsOfFile"成功,它不会分配变量'error'而且没有正文触摸这个变量.

变量'error'从哪里拿垃圾为什么第一次点击不包含垃圾?

当然花了几个小时后我解决了这个问题,强制(重新)初始化'nil':

NSError* error = nil;
Run Code Online (Sandbox Code Playgroud)

但上面的问题没有过期.

Jer*_*myP 5

变量error在堆栈上声明.将强[1]对象引用到堆栈时初始化为nil的特性是仅ARC特征,即如果将其关闭,则该变量将不再被初始化.

但是,在堆栈上分配的内存首先归零,只有在使用它包含垃圾之后才会归零.此外,垃圾本身可能巧合地为零.第一次进入这种方法时,内存可能是新分配的,因此error运气好了.在后续调用中,内存可能已被其他堆栈帧使用,因此error包含垃圾.

其他要点:

发送-retainCount到有效对象将永远不会返回0,因为-release取消分配对象而不是在计数为1时递减计数.

当你看到模式

 someResult = [someObject blahBlahError: &error];
Run Code Online (Sandbox Code Playgroud)

从技术上讲,不允许使用传回的值,error除非someResult是指示发生了错误.在您的示例中,您应该只尝试使用errorif dataOfFile设置为nil.

[1]感谢Nikolai的澄清.

  • +1 - 只是注意:进入方法时,即使是第一次,也不太可能在堆栈上获得归零内存.内存页在分配时归零的事实是正确的.但是之前没有使用堆栈内存的可能性很小.只有当堆栈中没有其他功能比当前功能更深入时,才会发生这种情况. (3认同)