无法理解NSError / NSObject指针传递行为

即使我已经阅读,我现在困惑于指针指针为什么NSError需要双重间接? (指针指针)和NSError * vs NSError **等等。

我做了一些思考,仍然有一些问题。

在这里我写了这个:

NSError *error = [NSError errorWithDomain:@"before" code:0 userInfo:nil]; NSLog(@"outside error address: %p", &error]; [self doSomethingWithObj:nil error:&error]; 

为了testing上面的NSError方法,我写了这个:

 - (id)doSomethingWithObj:(NSObject *)obj error:(NSError *__autoreleasing *)error { NSLog(@"inside error address: %p", error); id object = obj; if (object != nil) { return object; } else { NSError *tmp = [NSError errorWithDomain:@"after" code:0 userInfo:nil]; *error = tmp; return nil; } } 

但是我发现这两个日志logging地址是不同的。 这是为什么?

 2016-08-19 19:00:16.582 Test[4548:339654] outside error address: 0x7fff5b3e6a58 2016-08-19 19:00:16.583 Test[4548:339654] inside error address: 0x7fff5b3e6a50 

它们不应该是相同的,因为这只是一个简单的价值副本? 如果他们应该是不同的,如何指针指针最终指向相同的NSError实例?

调用者中的variables具有NSError*types。 地址的types是NSError* * 。 函数期望NSError* __autoreleasing * 。 因此,编译器创build一个types为NSError* __autoreleasing的隐藏variables,在调用之前将NSError*复制到隐藏variables中,并在调用之后将其复制回来以获取__autoreleasing权限的语义。

所以,在第一行初始化之后, error是一个指向NSError对象的指针。

在第一个日志中,您logging了该指针所在的地址。 这就是&address-of运算符的效果。 无论如何,这是地址获取传入doSomething方法。

你传入:pointer – > pointer – > nserror-object。

但要注意doSomething签名中的双重间接 。 autoreleasing注释使得很难发现,但它的NSError **

所以编译器会把你的参数和“解开”两次。

它从指针 – >指针 – > nserror – 对象开始。 然后,在第一个间接后,它成为指针 – > nserror对象。 然后在第二个间接后它变成了nserror对象。

恩戈,你logging了两件不同的事情。 第一个是指向nserror对象的指针的地址。 第二个是nserror-object本身的地址。

编辑:@MANIAK_dobrii指出,由error指向的对象本身是不同的前后大小写。

确实如此。 如果doSomething发生错误,那么它会在else子句中创build一个全新的NSError实例。 然后将其加载回error指针。 这就是为什么你会看到两个不同的地址,然后error指针完全指向另一个对象。