15

I've found various people/articles (e.g. this SO answer) suggesting that the value of pointers in Objective-C is not defined until you assign something to it. However, I'm finding in practice that they are automatically set to nil even before I call alloc - the following code runs for me without asserting:

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

Can/should I rely on this? Is it guaranteed or do I just happen to be running my compiler (Xcode) in some sort of debug mode? (I'm new to Objective-C).

A corollary question: what is the correct terminology to describe foo in the state at the end of the lines marked 1, 2 and 3? I imagine at least one of 1 & 2 them is termed 'uninitialised', and one of 2 & 3 is 'initialised', but which, and what do we call the third option?

Community
  • 1
  • 1
bacar
  • 9,761
  • 11
  • 55
  • 75
  • after alloc object is initialized and normally not ==nil. equals to nil it's error – theWalker Jan 30 '12 at 22:52
  • 1
    Possible duplicate of http://stackoverflow.com/questions/3989377/xcode-compiler-doesnt-set-my-variable-and-pointer-initial-value-to-0-or-nil – Usman Ismail Jan 30 '12 at 22:54

4 Answers4

33

Under ARC, all object pointers are set to nil upon initialization. When not running under ARC, or when using pointers to other datatypes, an uninitialized pointer will have a garbage value (and in fact reading from the pointer produces undefined behavior according to the C standard).


@Chuck points out something important, which is that this only applies to local variables. Any variable with static storage (function statics, or globals) and instance variables are always initialized to their respective zero value (which, for pointers, is nil/NULL).

Lily Ballard
  • 182,031
  • 33
  • 381
  • 347
  • 8
    Note that this is only true of local, nonstatic variables. Global, static and instance variables of object types *will* be initialized to nil according to the standard. – Chuck Jan 30 '12 at 22:54
  • @Chuck: Very good point. I will update my answer accordingly. – Lily Ballard Jan 30 '12 at 22:55
  • Can you link to the documentation that states this please? I thought the ARC link would have it, but it doesn't seem to (I searched the page for 'nil') – bacar Jan 30 '12 at 23:24
  • @bacar: See section 4.2 of the document I linked in my answer. Specifically, the bit that starts with ***Initialization***. – Lily Ballard Jan 30 '12 at 23:42
6

(For ARC, see Lily Ballard's answer)

Can/should I rely on this?

Nope - never rely on that. Stack memory is typically zeroed in debug builds (depends on your compiler settings). With optimization enabled, the compiler does not do that for you and you'll be given garbage values based on whatever happened to exist on the stack region last.

You can rely on zeroed ivars in your objects' initializers.

You can guard yourself from this with the static analyzer, and by enabling -Wuninitialized for your build configs when the optimization level is greater than -O0.

A corollary question: what is the correct terminology to describe foo in the state at the end of the lines marked 1, 2 and 3? I imagine at least one of 1 & 2 them is termed 'uninitialised', and one of 2 & 3 is 'initialised', but which, and what do we call the third option?

  1. Uninitialized
  2. An objc instance which has been allocated, but has not been initialized (not safe to use otherwise)
  3. An initialized objc instance or object.
Cœur
  • 37,241
  • 25
  • 195
  • 267
justin
  • 104,054
  • 14
  • 179
  • 226
  • I'll try turning them on if I can figure out how, then post back - just to check, does it also disable assertions? – bacar Jan 30 '12 at 22:56
  • @bacar: Disabling assertions is done with the `NS_BLOCK_ASSERTIONS` compiler macro. – Lily Ballard Jan 30 '12 at 22:57
  • Is there ever a situation where a pointer is automatically nil? If not, this alleviates most of the concerns I've had about sending messages to nil... – bacar Jan 30 '12 at 23:00
  • @bacar your program's static memory and your objects' ivars will be `nil` upon initialization. You can locate these cases by using the diagnostics I've mentioned in my (expanded) answer. – justin Jan 30 '12 at 23:07
1

An answer to your corollary question:

After #1, foo has been declared but is uninitialized.

After #2, foo has been allocated but is still uninitialized.

After #3, foo has been initialized.

In practice, you never want to separate steps 2 and 3, that is your code should be foo = [[NSString alloc] init]. The reason for this is that it is "dangerous" to allocate an object and not initialize it, or to initialize it improperly.

If you just do this foo = [NSString alloc] but forget to ever call init, it is not safe to use foo since it hasn't been initialized. Likewise, it is equally unsafe to do this [foo init] (notice the lack of reassignment to foo) because init can return a different reference to the initialized object than was originally allocated by alloc.

UIAdam
  • 5,303
  • 1
  • 27
  • 23
  • Is this terminology documented somewhere, or in a book, or just something you have observed in the community? – bacar Jan 30 '12 at 23:24
  • It is standard computer science terminology. – UIAdam Jan 30 '12 at 23:25
  • OK :-) I'm coming from a C++/C# background where objects are either constructed or they are not - no 'in between'. – bacar Jan 31 '12 at 00:17
  • Well, practically speaking the same is true for Objective-C objects as long as you follow the rules that I pointed out in my answer. – UIAdam Jan 31 '12 at 00:51
0

In ARC Environment objects are automatically set to nil. But it always a good practice to Assign value to objects during initialization.

I just ran a test with obj-c in ARC environment

NSString *testStr ;
if (testStr == nil) {
    NSLog(@"Test Successful");
}

OutPut : Test Successful

NSString *testStr = nil;
if (testStr == nil) {
    NSLog(@"Test Successful");
}

OutPut : Test Successful