我发现各种各样的人/文章(例如this SO answer)表明Objective-C中的指针值没有定义,直到你为它指定了东西。但是,我在实践中发现,即使在我调用nil
之前,它们也会自动设置为alloc
- 以下代码在没有声明的情况下为我运行:
NSString* foo; // 1
assert(foo==nil); // foo is nil
foo = [NSString alloc]; // 2
assert(foo!=nil); // after alloc, not nil.
foo = [foo init]; // 3
assert(foo!=nil); // still not nil
可以/我应该依靠这个吗?是保证还是我恰好在某种调试模式下运行我的编译器(Xcode)? (我是Objective-C的新手。)
一个必然的问题:在标记为1,2和3的行末尾的状态中描述foo
的正确术语是什么?我想象1和1中至少有一个2它们被称为“未初始化”,而2和2之一被称为“未初始化”。 3是'初始化',但是哪个,我们称之为第三个选项?
答案 0 :(得分:29)
在ARC下,所有对象指针在初始化时都设置为nil
。如果不在ARC下运行,或者在使用指向其他数据类型的指针时,未初始化的指针将具有垃圾值(实际上,从指针读取会根据C标准产生未定义的行为)。
@Chuck指出一些重要的东西,这只适用于局部变量。任何带有静态存储(函数静态或全局变量)和实例变量的变量总是初始化为它们各自的零值(对于指针,它是nil
/ NULL
)。
答案 1 :(得分:6)
(对于ARC,请参阅Kevin的回答)
可以/我应该依靠这个吗?
不 - 从不依赖于此。堆栈内存通常在调试版本中归零(取决于您的编译器设置)。启用优化后,编译器不会为您执行此操作,并且您将根据最后在堆栈区域中发生的任何事情给出垃圾值。
你可以依赖对象的初始值设定项中的归零 ivars 。
您可以使用静态分析器保护自己,并在优化级别大于-Wuninitialized
时为您的构建配置启用-O0
。
一个必然的问题:在标记为1,2和3的行末尾的状态中描述foo的正确术语是什么?我想象1和1中至少有一个2它们被称为“未初始化”,而2和2之一被称为“未初始化”。 3是'初始化',但是哪个,我们称之为第三个选项?
答案 2 :(得分:1)
对你的推论问题的回答:
在#1之后,foo已经宣布但未初始化。
在#2之后,foo已经分配但仍未未初始化。
在#3之后,foo已经初始化。
实际上,您永远不想将步骤2和3分开,即您的代码应为foo = [[NSString alloc] init]
。这样做的原因是分配一个对象而不是初始化它或者不正确地初始化它是“危险的”。
如果您只是执行此操作foo = [NSString alloc]
但忘记调用init,则使用foo是不安全的,因为它尚未初始化。同样,执行此操作同样不安全[foo init]
(注意缺少对foo的重新分配),因为init可以返回与初始化对象不同的引用,而不是最初由alloc分配的引用。
答案 3 :(得分:0)
在ARC环境中,对象自动设置为nil。但在初始化期间为对象分配值总是一个好习惯。
我刚刚在ARC环境中使用obj-c进行了测试
NSString *testStr ;
if (testStr == nil) {
NSLog(@"Test Successful");
}
OutPut :
测试成功
NSString *testStr = nil;
if (testStr == nil) {
NSLog(@"Test Successful");
}
OutPut :
测试成功