这个概念似乎让我感到困扰。为什么NSError对象需要将其指针传递给正在修改对象的方法?例如,不只是传递对错误的引用做同样的事情吗?
NSError *anError;
[myObjc doStuff:withAnotherObj error:error];
然后在doStuff中:
- (void)doStuff:(id)withAnotherObjc error:(NSError *)error
{
// something went bad!
[error doSomethingToTheObject];
}
为什么上述工作不能像大多数其他对象消息传递模式一样工作?为什么必须使用错误:(NSError **)错误?
答案 0 :(得分:93)
很简单:
如果将指向对象的指针传递给函数,该函数只能修改指针指向的内容。
如果将指针传递给指向对象的指针,则该函数可以修改指针以指向另一个对象。
在NSError的情况下,该函数可能想要创建一个新的NSError对象并向您传回指向该NSError对象的指针。因此,您需要双重间接,以便可以修改指针。
答案 1 :(得分:77)
当方法通常返回某个值但是如果失败则可能需要返回错误对象(类型为NSError**
)时使用NSError*
模式。在Objective-C中,方法只能返回一种类型的对象,但是这种情况下你想要返回两种。在需要返回额外值的C语言中,您需要指向该类型值的指针,因此要返回NSError*
,您需要NSError**
参数。一个更现实的例子就是:
// The method should return something, because otherwise it could just return
// NSError* directly and the error argument wouldn't be necessary
- (NSArray *)doStuffWithObject:(id)obj error:(NSError **)error
{
NSArray *result = ...; // Do some work that might fail
if (result != nil) {
return result;
} else {
// Something went bad!
// The caller might pass NULL for `error` if they don't care about
// the result, so check for NULL before dereferencing it
if (error != NULL) {
*error = [NSError errorWithDomain:...];
}
return nil; // The caller knows to check error if I return nil
}
}
如果您只有NSError*
参数而不是NSError**
,那么doStuff
永远无法将错误对象传递回其调用者。
答案 2 :(得分:8)
一个老问题,但我认为值得把它放在这里 -
实际罪魁祸首是NSError。如果查看其类引用,则不存在任何属性的setter方法,即域,代码或userInfo。所以没有办法,您可以只分配和初始化NSError,将其传递给方法,然后填充传递的NSError对象的信息。 (如果有一个setter方法,我们可能刚刚传递了一个NSError *并在方法中做了类似error.code = 1的事情。)
因此,如果出现错误,您必须在方法中生成一个新的NSError对象,如果您这样做,将其传递回调用者的唯一方法是使用NSError **参数。 (由于上述答案中解释的原因。)
答案 3 :(得分:6)
关于n8gray所说的替代声明:
因为您没有收到要发送消息的对象;你正在创建对象并返回它。您通常需要指针指向 - NSError *
- 变量参数,因为您一次只能对一件事使用return
语句,并且您已经在NO
使用它
答案 4 :(得分:0)
通过阅读上面的所有答案,我仍然无法全面了解情况。我在下面做的外行练习,终于让我明白了发生了什么。只是把它放在那里,以防其他初学者。
假设你有以下
@interface Class X
-(void) methodX:(NSMutableArray *)array;
@end
在代码的其他部分,您有以下顺序
ClassX *objectX = [[ClassX alloc] init];
NSMutableArray *arrayXX = [@[@(1), @(2)] mutableCopy];
//What is stored in arrayXX is the address in the heap at which the NSMutableArray object starts, lets call this address ZZZ
//array starting at address ZZZ in the heap now contains NSNUmbers @1,@2
[objectX methodX:array]
当您调用[objectX methodX:array]
时,该方法收到的内容是array
的副本。由于数组包含一个地址(即指针), copy 的特殊之处在于接收的是另一个地址为ZZZ的变量。
因此,如果methodX执行[array removeObjectAtIndex:0]
,那么从地址ZZZ开始的对象会受到影响(现在只包含一个NSNUmber @(2))。因此,当方法返回时,原始数组也会受到影响。
假设methodX确实array = [@[@(2)] mutableCopy];
,那么原始数组不会受到影响。这是因为你没有进入地址ZZZ并改变了一些东西。相反,您将方法接收的副本中的ZZZ覆盖到另一个地址YYY。 YYY地址是NSMUtableArray对象的开始,其中一个元素为NSNUmber @(2)。原始ZZZ地址仍包含带有两个元素的NSMUtableArray。 @(1)和@(2)。因此,当方法返回时,原始数组不受影响。