简体   繁体   中英

Why the buffer needs to be __unsafe_unretained on NSInvocation - getArgument:atIndex:?

I am working with NSInvocation and needed to retrieve one of the attributes from it.

I was using the following code, but I had some weird behaviour calling [invocation invoke]; :

NSString *propertyName = nil;
[invocation getArgument:&propertyName atIndex:3];

I read that in order to make it work under ARC, we need to use __unsafe_unretained :

__unsafe_unretained NSString *propertyName = nil;
[invocation getArgument:&propertyName atIndex:3];

It worked, good!! But I would like to understand why. Can anyone explain this?

The signature for -[NSInvocation getArgument:atIndex:] is

- (void)getArgument:(void *)buffer
        atIndex:(NSInteger)index

So buffer is untyped and not necessarily an object. ARC mandates that you use a non-retained reference (therefore the unretained part), which does not keep the referenced object alive and can dangle (therefore dangerous or unsafe ), so it has to be qualified as __unsafe_unretained , see also the clang specification , you have to tell ARC not to care about this piece of memory.

The use of NSInvocation is not really recommended anymore, it doesn't work well with ARC and is not available in Swift. As an alternative you could use -[NSObject methodForSelector:] .

The question is, who is responsible for modifying the retain count of the object (if it is even an object). I think it is also called the owner.

We could try to say that whoever makes the assignment should be. But NSInvocation lacks the knowledge to do that. It doesn't know whether you pass a __strong or a __weak, and it doesn't have to. This means that when assigning the value, the invocation does not know whether to actually retain the object or not, because it does not know whether the object will be released or not. Then, that responsibility is sent to the caller.

And, I would say, memory management should always be managed by the caller.

The difference with, let's say, NSError, for example, is that an NSError may be allocated by the function being called, that's why the parameter needs to be __autorelease. This is not the case for NSInvocation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM