4

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

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

我undersand,我会为我设置调用像这样

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:选项:错误:最后一个参数期望接收的指针而不是一个对象。其结果是执行以下操作不起作用 -

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

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

回答

3

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

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

NSError **errorPointer

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

所以,你要还声明NSError变量,并指定其地址作为errorPointer应指向变量:

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

现在你可以在errorPointer作为参数传递,和你如果调用方法时出现问题,稍后可以检查它。查看this post on NSInvocation获得更多帮助(帽子提示Mark Dalrymple指出博客帖子)

重要的是还要认识到,应该为您创建的参数考虑范围并将其传递到您的调用中。看看我问here的类似问题。

+2

“但是,既然你没有告诉它指向任何变量,它指向零。”什么?不,它没有定义 – user102008 2012-05-11 18:49:25

+0

“现在你可以传入errorPointer作为参数”你不解释如何传递它。 – user102008 2012-05-11 18:50:13

+2

#1在ARC下,未分配的本地指针变量被自动设置为零。在C或非ARC Obj-C中,你是正确的。 #2传递errorPointer作为第四个参数'[invocation setArgument:&errorPointer atIndex:4]' – edelaney05 2012-05-11 21:22:07

0

参数类型为NSError **,您可以从要获得错误信息的NSError *的地址获取该参数。要在NSInvocation中设置参数,您需要将参数值的地址传递给setArgument:,因此您需要将NSError **放入一个变量中(我在此称其为errPointer),并将其地址(将会是NSError ***)传递给setArgument:。之后您不需要errPointer变量。

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

edelaney05接受的答案很好,但我认为它需要对ARC进行一些微调。 (我不能添加评论,所以创建一个新的答案记录我发现了什么)

原样,我得到的编译错误: “指向非const类型‘NSError *’没有明确的所有权“

我研究这个,我发现我需要:

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

引用,导致我这样的回答:

NSInvocation & NSError - __autoreleasing & memory crasher

Automatic Reference Counting: Pointer to non-const type 'NSError *' with no explicit ownership

http://developer.apple.com/library/ios/#releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html

“__autoreleasing被用于表示通过引用传递(ID *)和返回时被自动释放参数”。