__strong ownership qualifier
Let’s see how the variables that are qualified with __strong work, using NSMutableArray class method “array” as an example. We see under the hood of calling the method and inside the method itself. Before that, please see the following source code.
{
id __strong obj = [[NSObject alloc] init];
}
Clang can display its output as assembly/machine code. For the sake of readability we have represented each excerpt below as its ObjC equivalent. With the output and the source code of the objc4 library, we are able to see what is going on under the hood. The above source code is rewritten as follows. Please note that sometimes we use pseudo code to make it more understandable.
/* pseudo code by the compiler */
id obj = objc_msgSend(NSObject, @selector(alloc));
objc_msgSend(obj, @selector(init));
objc_release(obj);
You can see that objc_msgSend is called twice for alloc and init method invocation. After that, objc_release is called to release the object when the variable scope is left. Although you can’t call the release method explicitly, you can see that release is automatically inserted in the pseudo code.
Calling the array method
Next, let’s see what happens when an object is not obtained by the alloc/new/copy/mutableCopy method group. The original source code is as follows.
{
id __strong obj = [NSMutableArray array];
}
This is ordinary-looking NSMutableArray class method “array”. The pseudo code of this is a bit different from the previous one.
/* pseudo code by the compiler */
id obj = objc_msgSend(NSMutableArray, @selector(array));
objc_retainAutoreleasedReturnValue(obj);
objc_release(obj);
The first objc_msgSend for the array method and the last objc_release are the same as the previous one. What is the objc_retainAutoreleasedReturnValue function call?
objc_retainAutoreleasedReturnValue function is for performance optimization. It is inserted because the NSMutableArray class method array is not in the alloc/new/copy/mutableCopy method group. The compiler inserts this function every time just after the invocation of a method if the method is not in the group. As the name suggests, it retains an object returned from a method or function after the object is added in autorelease pool.
objc_retainAutoreleasedReturnValue function expects that an objc_autoreleaseReturnValue function has been called inside the method. Any methods, that are not in the alloc/new/copy/mutableCopy group, have to call objc_autoreleaseReturnValue. For instance, NSMutableArray class method “array” calls this function.
Inside the array Method
Let’s see the implementation of the NSMutableArray class method “array” as the compiler-generated code.
+ (id) array
{
return [[NSMutableArray alloc] init];
}
This source code is converted as follows. It calls objc_autoreleaseReturnValue function at the last.
/* pseudo code by the compiler */
+ (id) array
{
id obj = objc_msgSend(NSMutableArray, @selector(alloc));
objc_msgSend(obj, @selector(init));
return objc_autoreleaseReturnValue(obj);
}
Any methods that return an object added to autorelease pool call objc_autoreleaseReturnValue function as in the above example. It adds an object to autorelease pool and returns it. But, in reality, objc_autoreleaseReturnValue doesn’t register it to autorelease pool all the time.
objc_autoreleaseReturnValue checks the caller’s executable code and if the code calls objc_retainAutoreleasedReturnValue function just after calling this method, it skips registering to the autorelease pool and just returns the object to the caller. objc_retainAutoreleasedReturnValue function is implemented to obtain such an object properly even if objc_autoreleaseReturnValue didn’t register the object to the autorelease pool. By co-operation of objc_autoreleaseReturnValue and objc_retainAutoreleasedReturnValue, the object bypasses being added to autorelease pool as shown in Figure3–1. So, performance will be improved.1
__________