In which situations do we need to write the __autoreleasing ownership qualifier under ARC?

后端 未结 3 673
醉梦人生
醉梦人生 2020-11-27 09:48

I\'m trying to complete the puzzle.

__strong is the default for all Objective-C retainable object pointers like NSObject, NSString, etc.. It\'s a strong

相关标签:
3条回答
  • 2020-11-27 10:21

    You're right. As the official documentation explains:

    __autoreleasing to denote arguments that are passed by reference (id *) and are autoreleased on return.

    All of this is very well explained in the ARC transition guide.

    In your NSError example, the declaration means __strong, implicitly:

    NSError * e = nil;
    

    Will be transformed to:

    NSError * __strong error = nil;
    

    When you call your save method:

    - ( BOOL )save: ( NSError * __autoreleasing * );
    

    The compiler will then have to create a temporary variable, set at __autoreleasing. So:

    NSError * error = nil;
    [ database save: &error ];
    

    Will be transformed to:

    NSError * __strong error = nil;
    NSError * __autoreleasing tmpError = error;
    [ database save: &tmpError ];
    error = tmpError;
    

    You may avoid this by declaring the error object as __autoreleasing, directly.

    0 讨论(0)
  • 2020-11-27 10:26

    Following up on Macmade's answer and Proud Member's follow up question in the comments, (would have also posted this as a comment but it exceeds the max character count):

    Here is why the variable qualifier of __autoreleasing is placed between the two stars.

    To preface, the correct syntax for declaring an object pointer with a qualifier is:

    NSError * __qualifier someError;
    

    The compiler will forgive this:

    __qualifier NSError *someError;
    

    but it isn't correct. See the Apple ARC transition guide (read the section that begins "You should decorate variables correctly...").

    To address to the question at hand: A double pointer cannot have an ARC memory management qualifier because a pointer that points to a memory address is a pointer to a primitive type, not a pointer to an object. However, when you declare a double pointer, ARC does want to know what the memory management rules are for the second pointer. That's why double pointer variables are specified as:

    SomeClass * __qualifier *someVariable;
    

    So in the case of a method argument that is a double NSError pointer, the data type is declared as:

    - (BOOL)save:(NSError* __autoreleasing *)errorPointer;
    

    which in English says "pointer to an __autoreleasing NSError object pointer".

    0 讨论(0)
  • 2020-11-27 10:28

    The definitive ARC specification says that

    For __autoreleasing objects, the new pointer is retained, autoreleased, and stored into the lvalue using primitive semantics.

    So for example, the code

    NSError* __autoreleasing error = someError;
    

    actually gets converted to

    NSError* error = [[someError retain] autorelease];
    

    ... which is why it works when you have a parameter NSError* __autoreleasing * errorPointer, the called method will then assign the error to *errorPointer and the above semantics will kick in.

    You could use __autoreleasing in a different context to force an ARC object into the autorelease pool, but that's not terribly useful since ARC only seems to use the autorelease pool at method return and already handles that automatically.

    0 讨论(0)
提交回复
热议问题