NSInvocation and memory issues [duplicate]

。_饼干妹妹 提交于 2019-12-23 07:47:49

问题


So I come from the Java world where we are blissfully ignorant of memory management issues. For the most part, ARC has saved my butt, but here is something that has got me stumped. Basically I am using NSInvocations for some stuff, and I ran into some nasty memory issues before I made the following code modifications. Since I made these modifications, the memory crashes have gone away, but I am usually very scared of code that I dont understand. Am I doing this right?

Before: all sorts of memory issues:

NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[[target class] instanceMethodSignatureForSelector:selector]];
[invocation setSelector:selector];
[invocation setTarget:target];
[invocation setArgument:&data atIndex:2];
[invocation setArgument:&arg atIndex:3];
[invocation invoke];

NSString *returnValue;
[invocation getReturnValue:&returnValue];

After : No memory issues, but I am not sure I got this right:

NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[[target class] instanceMethodSignatureForSelector:selector]];
[invocation setSelector:selector];
[invocation setTarget:target];
[invocation setArgument:&data atIndex:2];
[invocation setArgument:&arg atIndex:3];
[invocation invoke];

CFTypeRef result;
[invocation getReturnValue:&result];

if (result)
    CFRetain(result);

NSString *returnValue = (__bridge_transfer NSString *)result;

Edit:

I Just wanted to add on basis of the answer below, I used objc_msgSend, as such.:

NSString * returnValue = objc_msgSend(target, selector, data, arg);

And it solves all the memory issues, plus looks much simpler. Please comment if you see any issues with this.


回答1:


I will answer your question like this: Don't use NSInvocation. It's just a friendly advice to avoid that if possible.

There are many nice ways to do callbacks in Objective-C, here are two that may be useful for you:

  • Blocks: Defined in context, choose any argument count and types, possible issues with memory too. There are many resources on how to use them.
  • performSelector: max 2 object arguments, invoked using:

    [target performSelector:selector withObject:data withObject:args];
    

In addition, when I need to invoke a selector with 4 arguments I still don't use NSIvocation, but rather call objc_msgSend directly:

id returnValue = objc_msgSend(target, selector, data, /* argument1, argument2, ... */);

Simple.

Edit: With objc_msgSend you need to be careful with the return value. If your method returns an object, use the above. If it returns a primitive type, you need to cast the objc_msgSend method so the compiler knows what's going on (see this link). Here's an example for a method that takes one argument and returns a BOOL:

// Cast the objc_msgSend function to a function named BOOLMsgSend which takes one argument and has a return type of BOOL.
BOOL (*BOOLMsgSend)(id, SEL, id) = (typeof(BOOLMsgSend)) objc_msgSend;
BOOL ret = BOOLMsgSend(target, selector, arg1);

If your method returns a struct, things are a bit more complicated. You may (but not always) will need to use objc_msgSend_stret -- see here for more info.

Edit: - this line have to be added to the code, or Xcode will complain:

#import <objc/message.h>

or

@import ObjectiveC.message;



回答2:


You should generally consider blocks as a superior alternative where possible (they succeeded NSInvocation).

As far as the return value, you can use this:

CFTypeRef result = NULL;
[invocation getReturnValue:&result];    
NSString *returnValue = (__bridge NSString *)result;

The underlying issue here is that -getReturnValue: does not return an out object, as far as ARC is concerned. Therefore, it is likely getting the reference count operations wrong (the compiler adds these for you in ARC), because -getReturnValue:'s parameter is void*, not an out object (e.g. NSObject**).



来源:https://stackoverflow.com/questions/17509702/nsinvocation-and-memory-issues

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!