如何使用将指向对象的指针作为参数的方法创建NSInvocation对象



我想使用一个将指向NSError对象的指针作为参数的方法来创建一个NSInvocation对象。这方面的一个例子是方法

- (BOOL)writeToFile:(NSString *)path options:(NSDataWritingOptions)mask error:(NSError **)errorPtr

我强调我会像这个一样设置我的调用

NSData *myData = [[NSData alloc] init];
SEL writeToFileSelector = @selector(writeToFile:options:error:);
NSMethodSignature *signature = [NSData instanceMethodSignatureForSelector:writeToFileSelector];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
[invocation setTarget:myData];
[invocation setSelector:writeToFileSelector];
NSString *string = [NSString stringWithFormat:@"long cat"];
NSDataWritingOptions *dataOptions;
*dataOptions = NSDataWritingFileProtectionComplete;
[invocation setArgument:&string atIndex:2];
[invocation setArgument:&dataOptions atIndex:3];

对于writeToFile:Options:Error:最后一个参数应接收指针而不是对象。因此,执行以下操作不起作用-

NSError *err = nil;
[invocation setArgument:&err atIndex:4];

解决方案可能是创建一个指向指针的指针,这似乎是合乎逻辑的,但这会导致编译器警告。我不知道如何正确执行它,而不会造成内存管理问题。

您创建的参数与传递给方法的任何其他参数相同。

正如您所指出的,方法签名需要一个NSError**作为其最后一个参数(索引4)。所以,你需要声明一个,但有一点困难。

NSError **errorPointer

为您提供一个指向NSError变量的变量。但是,由于你没有告诉它指向任何变量,它指向零。因此,当您启动调用时,选择器将无法更改错误指针指向的变量。换句话说,这就像调用[myData writeToFile:string options:dataOptions error:NULL]一样。

因此,您还需要声明一个NSError变量,并将其地址指定为errorPointer应该指向的变量:

NSError *error;
NSError **errorPointer = &error;

现在,您可以将errorPointer作为参数传入,以后如果调用该方法时出现问题,您就可以对其进行检查。查看NSInvocation上的这篇文章以获得更多帮助(Mark Dalrymple指出博客文章的帽子提示)

同样重要的是要认识到,应该为您创建并传递到调用中的参数考虑范围。看看我在这里问的一个类似的问题。

edelaney05接受的答案很棒,但我认为ARC需要稍微调整一下。(我还不能添加评论,所以创建一个新的答案来记录我的发现)

按原样,我得到了编译错误:"指向没有显式所有权的非常量类型'NSError*'的指针"

我对此进行了研究,发现我需要:

 NSError * __autoreleasing error = nil;
 NSError * __autoreleasing *errorPointer = &error;

导致我得出这个答案的参考文献:

NSInvocation&NSError-__自动释放&内存崩溃

自动引用计数:指向非常量类型的指针';NSError*';没有明确的所有权

http://developer.apple.com/library/ios/#releasenotes/ObjectiveC/RN-过渡到ARC/简介/简介.html

"__autorelasing用于表示通过引用(id*)传递并在返回时自动释放的参数。"

参数类型是NSError **,它是从您希望写入错误的NSError *的地址中获得的。要在NSInvocation中设置参数,您需要将参数值的地址传递给setArgument:,因此您需要将NSError **放在一个变量中(我在这里称之为errPointer),并将其地址(将是NSError ***)传递给setArgument:。之后不需要errPointer变量。

NSError *err = nil;
NSError **errPointer = &err;
[invocation setArgument:&errPointer atIndex:4];

最新更新