NSInvocation和内存问题

所以我来自Java世界,我们对内存pipe理问题非常无知。 大多数情况下,ARC已经救了我的屁股,但是这是让我难住的东西。 基本上我使用NSInvocations的东西,我遇到了一些讨厌的内存问题,我做了下面的代码修改。 由于我做了这些修改,内存崩溃已经消失,但我通常非常害怕我不明白的代码。 我做对了吗?

之前:各种内存问题:

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]; 

之后:没有内存问题,但我不知道我有这个权利:

 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; 

编辑:

我只是想在下面的答案的基础上添加,我用objc_msgSend,如:

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

它解决了所有的内存问题,再加上看起来更简单。 如果您发现任何问题,请发表评论。

我会像这样回答你的问题: 不要使用NSInvocation 如果可能 ,这只是一个友好的build议。

在Objective-C中有许多很好的方法来做callback,下面是对你有用的两个方法:

  • :在上下文中定义,select任何参数数量和types,也可能与内存有关的问题。 有很多关于如何使用它们的资源。
  • performSelector :最多2个对象参数,使用以下方法调用:

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

另外,当我需要调用带有4个参数的select器时,我仍然不使用NSIvocation ,而是直接调用objc_msgSend

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

简单。

编辑:使用objc_msgSend你需要注意返回值。 如果你的方法返回一个对象,使用上面的。 如果它返回一个原始types,则需要objc_msgSend方法,以便编译器知道发生了什么( 请参阅此链接 )。 下面是一个带有一个参数并返回一个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); 

如果你的方法返回一个结构,事情有点复杂。 你可能 (但不总是)将需要使用objc_msgSend_stret – 在这里看到更多的信息 。

编辑: – 这行必须添加到代码,否则Xcode会抱怨:

 #import <objc/message.h> 

要么

 @import ObjectiveC.message; 

在可能的情况下,您通常应该将块视为一种优越的替代scheme(他们成功地实施了NSInvocation )。

至于返回值,你可以使用这个:

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

这里的根本问题是, -getReturnValue:不会返回一个out 对象 ,就ARC而言。 因此,引用计数操作很可能是错误的(编译器会在ARC中为你添加这些操作),因为-getReturnValue:的参数是void* ,而不是out对象(例如NSObject** )。