I have a function declared like this:
- (void)loadWithCompletion:(MyCompletion)completion error:(NSError**)error;
The function takes a double pointer to an NSError so I can report errors to the caller. The completion (and possibly the error) will occur some time after the function is called. I need to store the NSError** as a property so I can use it when the aforementioned time passes.
#property(nonatomic, assign) NSError** error;
This property declaration gives me the error:
Pointer to non-const type NSError* with no explicit ownership.
add __autoreleasing between the **, to give NSError*__autoreleasing* error
In Xcode 5.1 the ARC warning "Implicit ownership types on out parameters" was turned on by default (it used to be off). So with 5.1 this warning started appearing when there was no specified ownership.
The compiler assumes you want autoreleased, which is usually correct, but it's better that the author think about it and specify what the really want.
Usually you want the output parameter to be autoreleasing, similar to a function result. The caller will get an autoreleased object and will need to store it in a strong variable if they want to retain ownership.
Related
the Code: [NSClassFromString(#"Test") gotoTest];
usage ARC with Error: No known class method for selector 'gotoTest'
but in MRC warning no error.
Way ARC from warning becomes an error ? do you have any reference? I want to know the essential reason.
You did not include the warning under MRC:
Class method '+gotoTest' not found (return type defaults to 'id')
and this contains a vital clue – the compiler is looking for the return type. Under MRC it assumes id and will let you assign the result as an object reference. If you mess up and the return type is, say, float, things will probably go wrong.
Under ARC it is the compilers job to do the memory management of any returned value, and to do this correctly it needs to the the type. So if it can't determine the return type it produce an error.
Your code fragment suggests you know the selector takes no arguments and returns no value, so declare it as such. If you've no class with the method you can use a protocol, something like:
#protocol GotoTest
+ (void) gotoTest;
#end
will do. Now the compiler knows the types and your code will compile under ARC.
HTH
Can someone please explain to me the purpose of having __autoreleasing in the following sample code block?
- (void)execute:(NSError * __autoreleasing *)error {
// do stuff, possibly assigning error if something went wrong
}
I removed the __autoreleasing and everything still seems to compile/run fine. I started using obj-c post ARC so I never really learned/understood all those double underscore thingamajigs. I've read the ARC transition guide, but I don't fully understand their NSError example.
Consider how ARC works with variables - each reference variable has a mode (implicit or explicit): strong, weak, etc. This mode let's ARC know how to handle reads and writes to that variable; e.g. for a strong variable reading requires no additional action while writing requires releasing the existing reference in the variable before it is replaced by the new one. ARC needs to know the mode of any variable in order to function.
Now consider variables that themselves are passed by reference, e.g. for your execute you'll have a call along the lines of:
NSError *myError = nil;
...
[someObject execute:&myError]; // pass the variable itself by reference, not the variables value
and the body of execute will contain an assignment along the lines of:
- (void)execute:(NSError * __autoreleasing *)error
{
...
if (error != NULL)
*error = [NSError ...]; // assign indirectly via the reference to a variable
...
}
Now for that indirect assignment ARC needs to know the mode of the referenced variable so it knows how to read and write. That is what the __autoreleasing is in the declaration, it tells ARC that it has been passed a reference to a variable whose mode is autoreleasing, and that tells ARC how to read and write the contents of the variable. Remove the __autoreleasing and a default mode will be assumed, and in this case I'd suggest being explicit is certainly good.
The autoreleasing mode means the variable contains a reference which is not owned, reads should retain if necessary and writes can just write. It is used mainly for variables passed by reference.
You might notice that in the example above the variable myError has mode strong (implicitly) and yet it is passed by reference as autoreleasing - the compiler handles this automatically by introducing a temporary autoreleasing variable, copying without retaining the current reference in myError into it, and passing the temporary by reference as the argument to execute:. After the call returns the compiler does a normal assignment from the temporary to myError, which results in any old reference being released and the returned one retained.
For more details see Apple's Transitioning to ARC Release Notes
Followup to Comments
Q: Is __autoreleasing implicitly set?
A: Well Apple's document is not specific, but the Clang documentation says it is implicit for indirect parameters. As above I'd recommend being explicit, clarity is a Good Thing™.
Q: Does the placement matter?
A: Yes, and no... This is a C declaration, the stuff of quiz questions ("What does the following declare..."). The qualifier should be between the two asterisks as it is a pointer to a (variable of type) autoreleasing pointer to an object, but Apple state the compiler is "forgiving" without being specific of what it forgives. Play it safe, put it in the right place.
Q: Should you not test for error being NULL before doing the indirect assignment?
A: Of course you should, somewhere before you do the indirection. The code shown is just an outline and such detail was elided and covered by the ...’s. However as it has been raised a few times over the years maybe I elided too much, a suitable if has been added.
I'm overriding - (BOOL) isEqual:(id)object in a custom class.
Out of the 4 choices, which are __weak, __strong, __autoreleasing, and __unsafe_unretained, which should I be using on the parameter for the isEqual: method signature?
I'm thinking this is where the problem is, since when I'm trying to add an instance of my class to a NSMutableDictionary, I'm getting an EXC_BAD_ACCESS(code=2, address=0x10) at the declaration of the method.
In other words, the line at which the debugger gets the EXC_BAD_ACCESS is:
- (BOOL) isEqual:(id __strong)object {
before any of the method body is executed.
The correct answer was "If you're getting bad access, then you're trying to read or write to an area that doesn't have what you think it has in it.", per #Dustin Rowland in the comments.
By default, ARC uses __strong, which means that the argument is held via a retain/release for the duration of its use inside the method. To lead to EXC_BAD_ACCESS, an object (either the argument itself, or any other object used in the method calls inside the isEqual: implementation) has to be over-released when accessing it. This cannot be fixed by changing the qualifier.
Sidenote: Be careful though by expecting to see anything to change when you change the qualifier. The compiler optimizations may decide that it is safe to skip some calls. For example, add the following code to a file and look at the assembly (Product -> Generate Output -> Assembly File) for Archiving (which uses -Os).
- (void)logObject:(id)o
{
NSLog(#"%#", o);
}
- (void)call
{
id o = [[NSObject alloc] init];
[self logObject:o];
}
Although the parameter of logObject: is the default __strong, no retain/release is done in the assembly output. Changing the parameter of -logObject: to __strong, __weak, __unsafe_unretained or __autoreleasing gives exactly the same assembly output. If you duplicate the line with the NSLog however, the assembly code changes for the different type qualifiers.
I have a class RemoteImageLoader which has a method loadImage:
- (void) loadImage: (NSString*) url setTarget:(NSData **)target;
I used a NSData** here because I need to indirectly return NSData* , just like some typical method:
- (BOOL)save:(NSError**)
since the method will actually invoke another asynchronous method, I have to save the target as a member variable so I can access it later. but when I define a NSData ** member variable:
#interface RemoteImageLoader : NSObject
#property NSData** target;
#end
the compiler complains that "Pointer to non-const type 'NSData*' with no explicit ownership". I've done some search on google, but find no answer of it. Could anyone help me with this? Thanks a lot
and I've tried to replace the declaration to
#interface RemoteImageLoader : NSObject
#property NSData * __autoreleasing * target;
#end
but the problem still exists
The ARC Transition Notes recommend you declare indirect pointers to NSData and NSError objects in your case with __autoreleasing, like (NSData * __autoreleasing *)target;
__autoreleasing is known as a lifetime qualifier which tells the compiler to return an autoreleased instance of the object.
Because of this, a rewrite of your method signature is required.
- (void) loadImage: (NSString*) url setTarget:(NSData* __autoreleasing *)target;
Be warned, __autoreleasing objects are extremely short lived. Declare your NSData** as __strong to override the default __autoreleasing for a longer lifetime.
I think your method signature is going to cause trouble. A caller is very likely to assume that the pointed-to pointer is filled in as soon as your method returns. Similarly, they are very likely to pass the address of a stack variable which won't be valid for long. Lastly, your method provides no means for the caller to know when the pointed-to pointer has been filled with a value.
You are probably better off taking a completion block from the caller. The completion block will receive an NSData pointer as an argument. Something like:
- (void) loadImage: (NSString*) url completionHandler:(void (^)(NSData* data))block;
This also mirrors the underlying framework API I presume you're using, which is always good for reducing "impedance mismatch".
As for the specific narrow issue you're encountering from the compiler, I suspect the issue is that the compiler can't know if it should emit retains and releases when you assign to *target. It wants you to explicitly declare the ownership characteristic of the pointed-to pointer. I can't check at the moment, but I guess that declaring it as __strong NSData** target would work. That is, it's not interested in whether target owns what it's pointing at, since one can't own a pointer. It's interested in whether the NSData* pointer to which target points owns the NSData object to which it points.
I can't be sure what you are trying to do without seeing your code, but why are you trying to create a pointer to an NSData object (Which is a pointer to NSData). Because you are creating a pointer to a pointer which is probably why you are getting the error. Try removing one of the pointers and see what happens.
Generally, when you do this sort of thing outside of ARC you do something like:
NSData* returnedParm;
[someObj doSomething:&returnedParm];
on the caller's side. I don't see your equivalent of my returnedParm above. (I've never tried this with ARC, but I'd think the basics would have to be similar.)
Declaring a property as NSData** is declaring a pointer to a non-object and it would not be retained (because there's no object to retain).
My guess is that you should prototype your function as:
-(void)doSomething:(NSData* __autoreleasing*)theReturnParm
and assign to it inside that function using *theReturnParm = something;.
Then on the calling side you'd have your returnedParm as an autoreleased value (so if you want to preserve it you should relatively quickly assign it to a strong pointer).
Assume the following code under ARC,
typedef void (^MyResponseHandler) (NSError *error);
#interface MyClass : NSObject
{
MyResponseHandler _ivarResponseHandler;
}
- (void)myMethod:(MyResponseHandler)responseHandler
{
_ivarResponseHandler = responseHandler;
...
}
Question: Is the block automatically copied to the heap when assigned to the ivar?
My previous question implied that it is copied when assigned through a #property. But, today I used the above code and received an EXC_BAD_ACCESS that was fixed by changing to
_ivarResponseHandler = [responseHandler copy].
Edit: My previous answer was likely wrong.
Some selected excerpts from the ARC docs say:
3. Retainable object pointers
A retainable object pointer (or retainable pointer) is a value of a retainable object pointer type (retainable type). There are three kinds of retainable object pointer types:
block pointers (formed by applying the caret (^) declarator sigil to a function type)
4.2. Semantics
Assignment occurs when evaluating an assignment operator. The semantics vary based on the qualification:
For __strong objects, the new pointee is first retained; second, the lvalue is loaded with primitive semantics; third, the new pointee is stored into the lvalue with primitive semantics; and finally, the old pointee is released. This is not performed atomically; external synchronization must be used to make this safe in the face of concurrent loads and stores.
4.4.1. Objects
If an object is declared with retainable object owner type, but without an explicit ownership qualifier, its type is implicitly adjusted to have __strong qualification.
7.5. Blocks
With the exception of retains done as part of initializing a __strong parameter variable or reading a __weak variable, whenever these semantics call for retaining a value of block-pointer type, it has the effect of a Block_copy. The optimizer may remove such copies when it sees that the result is used only as an argument to a call.
So I think the answer is maybe, depending on the optimizer.
Your problem and solution indicate that my answer to your other question was probably wrong. I based it on the last paragraph of section 7.5 of the clang Objective-C Automatic Reference Counting documentation:
With the exception of retains done as part of initializing a __strong parameter variable or reading a __weak variable, whenever these semantics call for retaining a value of block-pointer type, it has the effect of a Block_copy. The optimizer may remove such copies when it sees that the result is used only as an argument to a call.
I took “these semantics” to mean the whole document, but if “these semantics” to refers to only section 7.5, then ARC only inserts a Block_copy for a block that is captured by a block.