为什么NSError需要双重间接? (指针指针)

这个概念似乎困扰着我。 为什么NSError对象需要将其指针传递给修改对象的方法? 例如,不只是传递一个错误的引用做同样的事情?

NSError *anError; [myObjc doStuff:withAnotherObj error:error]; 

然后在doStuff中:

  - (void)doStuff:(id)withAnotherObjc error:(NSError *)error { // something went bad! [error doSomethingToTheObject]; } 

为什么上面的工作不像大多数其他对象消息传递模式那样工作? 为什么我们必须使用错误:(NSError **)错误?

当一个方法正常返回某个值时,使用NSError**模式,但如果失败,可能需要返回一个错误对象(types为NSError* )。 在Objective-C中,一个方法只能返回一种types的对象,但是这种情况下你想返回两个。 在类C语言中,当你需要返回一个额外的值时,你需要一个指向该types值的指针,所以要返回一个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将永远无法将该错误对象传回给它的调用者。

很简单:

如果将指针传递给函数的对象,该函数只能修改指针指向的内容。

如果你传递一个指向一个对象的指针,那么函数可以修改指针指向另一个对象。

在NSError的情况下,该函数可能需要创build一个新的NSError对象,并传回一个指向该NSError对象的指针。 因此,你需要双重间接,以便指针可以被修改。

n8gray说的另一种说法是:

因为你没有收到发送消息的对象; 你正在创build对象并返回它。 您通常需要指向NSError *variables的指针,因为您一次只能在一个事物上使用return语句,而您已经使用了NO

一个古老的问题,但我认为它的价值在这里 –

实际的罪魁祸首是NSError 。 如果你看看它的类的引用,没有任何setter方法的任何属性,即域,代码或userInfo。 所以没有办法,你可以只分配和初始化一个NSError,把它传递给方法,然后在传递的NSError对象上填充信息。 (如果有一个setter方法,我们可以通过一个NSError *并在方法中做了类似error.code = 1的操作。)

所以如果有错误,你必须在方法中生成一个新的NSError对象,如果你这样做,唯一的方法将它传回给调用者是有一个NSError **参数。 (由于上述答案中解释的原因)

通过阅读上面的所有答案,我仍然没有得到完整的画面。 我在下面做的外行工作,终于帮助我了解发生了什么。 只要把它放在那里,以防止其他初学者。

假设你有以下

 @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副本 。 由于数组包含一个地址(即是一个指针),所以复制是特殊的,因为接收到的是地址为ZZZ的另一个variables。

所以,如果methodX [array removeObjectAtIndex:0] ,那么从地址ZZZ开始的对象会受到影响(现在只包含一个NSNUmber @(2))。 所以,当方法返回时,原始数组也会受到影响。

假设改为methodX,那么array = [@[@(2)] mutableCopy]; 那么原始数组不会受到影响。 这是因为你没有进入ZZZ,改变了一些东西。 相反,您将方法接收到的副本中的ZZZ重写为不同的地址YYY。 YYY地址是一个元素NSNUmber @(2)的NSMUtableArray对象的开始。 原始的ZZZ地址仍然包含一个带有两个元素的NSMUtableArray。 @(1)和@(2)。 所以,当方法返回时,原始数组不受影响。