I have some Objective C code compiled with ARC:
void func(void) {
NSString *string;
// Do some stuff. Maybe return early.
string = @"initialized";
// Other stuff.
}
How does ARC handle an uninitialized object pointer? I assume that, like a C pointer, string
initially contains stack garbage. If so, then how does ARC know what to do with it if, say, I were to return before initializing the variable?
Do I need to initialize it to, say, nil
, to avoid memory leaks?
Does it matter if the reference was to a dispatch object or block instead of an NSObject
?
I assume that, like a C pointer,
string
initially contains stack garbage.
This is actually not the case. From the Clang ARC docs:
It is undefined behavior if the storage of a
__strong
or__weak
object is not properly initialized before the first managed operation is performed on the object, or if the storage of such an object is freed or reused before the object has been properly deinitialized.
i.e., garbage object pointers are invalid under ARC rules
Storage for a
__strong
or__weak
object may be properly initialized by filling it with the representation of a null pointer, e.g. by acquiring the memory withcalloc
or usingbzero
to zero it out. A__strong
or__weak
object may be properly deinitialized by assigning a null pointer into it. A__strong
object may also be properly initialized by copying into it (e.g. withmemcpy
) the representation of a different__strong
object whose storage has been properly initialized; doing this properly deinitializes the source object and causes its storage to no longer be properly initialized.
i.e., strong
references are valid when they either point to nil
or a valid object pointer. (weak
references are a little more complicated)
The crux:
These requirements are followed automatically for objects whose initialization and deinitialization are under the control of ARC:
- objects of static, automatic, and temporary storage duration
- instance variables of Objective-C objects
- elements of arrays where the array object’s initialization and deinitialization are under the control of ARC
- fields of Objective-C struct types where the struct object’s initialization and deinitialization are under the control of ARC
- non-static data members of Objective-C++ non-union class types
- Objective-C++ objects and arrays of dynamic storage duration created with the new or new[] operators and destroyed with the corresponding delete or delete[] operator
They are not followed automatically for these objects:
- objects of dynamic storage duration created in other memory, such as that returned by malloc
- union members
i.e., almost all variables are actually automatically nil
ed out by ARC by default to make them valid for use.
So, no, you don't need to explicitly nil
out a local variable defined this way because it will be done automatically (though it's typically good practice to give explicit default values to make the behavior more obvious), and no, it doesn't matter whether the object is a dispatch object, block, or a subclass of NSObject
(because they are all Objective-C objects with the same behavior).
You would need to be careful about properly zeroing out object pointers which are contained in a union
or otherwise manually allocated using malloc
, but these cases are very uncommon.