我想使用一个将指向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指出博客文章的帽子提示)
同样重要的是要认识到,应该为您创建并传递到调用中的参数考虑范围。看看我在这里问的一个类似的问题。
按原样,我得到了编译错误:"指向没有显式所有权的非常量类型'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];