When is NS_RETURNS_RETAINED needed?

前端 未结 2 419
灰色年华
灰色年华 2021-02-07 15:18

Take the below example:

- (NSString *)pcen NS_RETURNS_RETAINED {
    return (__bridge_transfer NSString *)CFURLCreateStringByAddingPercentEscapes(NULL, (__bridge         


        
2条回答
  •  温柔的废话
    2021-02-07 16:11

    First Example

    Is it correct to put the NS_RETURNS_RETAINED there?

    It is incorrect -- no attribute is necessary here. Adding the attribute would go against naming conventions, which are very important to follow.

    In more detail, no attribute is required because the reference is transferred in the example using (__bridge_transfer NSString*). One might suppose that a CFCreated-Reference may need something more, but (__bridge_transfer NSString*) is all that is needed to transfer that reference off to ARC; for it to manage for you.

    If you were to have typecasted using (__bridge NSString*)CF_*_Create_*_, then the reference returned by the CFCreate function would not be transferred to ARC, and a leak would be introduced.

    (As an alternative, that leak could be avoided if you opted to release the returned string explicitly (e.g. using CFRelease).)

    Second Example

    However, the graphics context it's getting it from was created within the scope of the method, so is it correct to also have NS_RETURNS_RETAINED here?

    It is not correct or necessary to use an attribute. ARC uses naming conventions and attributes to determine the reference count operations to add -- It understands your program.

    Unlike the first example, an explicit __bridge_transfer should not be made.

    Adding the attribute would break naming conventions.

    Third Example

    - (NSArray *)places 
    ...
    

    No idea what to do here, as the returned object could be newly created or not.

    Again, no attribute should be used. An explicit __bridge_transfer should not be made. ARC understands ObjC conventions, including returning existing and newly created objects. It will insert the right reference count operations for both paths.

    And one last question; presumably NS_RETURNS_RETAINED isn't required if the object returned is the result of an autorelease'ed method. So say the return in the last example was amended to

    return [NSArray arrayWithObject:@"Unknown"];
    

    Again, no attribute is needed. An explicit transfer should not be made.

    Only a handful of uses of the attribute exist across all system libraries.


    I really, really, really, really advise against using these attributes, particularly:

    • where dynamic dispatch is involved (which all objc methods would qualify as)
    • where the parameters (consume) and results (returns retained) are ObjC types

    The rationale is that reference transfers should be local to the implementations, and there is rarely a real need to deviate from that; backwards compatibility is probably the "best" reason I can think of. If you have control of your code, just update it to do the right thing wherever possible rather than introducing these attributes. This can be accomplished by adhering to naming conventions, and by transferring references to ARC where appropriate.

    For some examples of the errors you can run into using attributes and deviating from naming conventions, see: Deep copy of dictionaries gives Analyze error in Xcode 4.2 .

    Another good reason to stick with naming conventions is that you don't always know how your program will be used. If somebody wants to use your program in MRC translations, then they will have to write unusual programs which read like this:

    someplace

    - (NSString *)name NS_RETURNS_RETAINED;
    

    elsewhere

    NSString * name = obj.name;
    NSLog(@"%@", name);
    [name release]; // << ME: not a mistake. triple checked.
    

提交回复
热议问题