环境:Mac OS X 10.9,Xcode 5.0.2
我为OS X创建标准Cocoa应用程序并在项目设置中禁用ARC.添加一个按钮"运行":
文件"AppDelegate.h":
#import@interface AppDelegate : NSObject @property (assign) IBOutlet NSWindow *window; - (IBAction)clickRun:(id)sender; @end
文件"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
当运行程序和第一次单击按钮控制台输出时:
" [1]保留错误计数:0 " - 当然为零因为变量'错误'未初始化
" [2]保留错误计数:0 " - 第二个零告诉我们"dataWithContentsOfFile"成功读取文件的方法.
并且调试器始终说出变量'error'键入'nil'.
但是当我第二次单击按钮时,调试器会中断:
NSLog(@"[1]保留错误计数:%lx",[错误retainCount]);
并显示消息"EXC_BAD_ACCESS"和变量'error'包含垃圾,当然[error retainCount]得到分段错误.但这有点奇怪,因为如果方法"dataWithContentsOfFile"成功,它不会分配变量'error'而且没有正文触摸这个变量.
变量'error'从哪里拿垃圾为什么第一次点击不包含垃圾?
当然花了几个小时后我解决了这个问题,强制(重新)初始化'nil':
NSError* error = nil;
但上面的问题没有过期.
变量error
在堆栈上声明.将强[1]对象引用到堆栈时初始化为nil的特性是仅ARC特征,即如果将其关闭,则该变量将不再被初始化.
但是,在堆栈上分配的内存首先归零,只有在使用它包含垃圾之后才会归零.此外,垃圾本身可能巧合地为零.第一次进入这种方法时,内存可能是新分配的,因此error
运气好了.在后续调用中,内存可能已被其他堆栈帧使用,因此error
包含垃圾.
其他要点:
发送-retainCount
到有效对象将永远不会返回0,因为-release
取消分配对象而不是在计数为1时递减计数.
当你看到模式
someResult = [someObject blahBlahError: &error];
从技术上讲,不允许使用传回的值,error
除非someResult
是指示发生了错误.在您的示例中,您应该只尝试使用error
if dataOfFile
设置为nil.
[1]感谢Nikolai的澄清.