即使我已阅读Why does NSError need double indirection? (pointer to a pointer)和NSError * vs NSError **等等,我现在也被指针指针弄糊涂了。
我已经做了一些思考,但仍然有一些问题。
我在这里写道:
NSError *error = [NSError errorWithDomain:@"before" code:0 userInfo:nil];
NSLog(@"outside error address: %p", &error];
[self doSomethingWithObj:nil error:&error];
为了测试上面的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;
}
}
但我发现两个日志记录地址不同。那是为什么?
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
实例?
答案 0 :(得分:4)
调用者中的变量的类型为NSError*
。地址的类型为NSError* *
。函数期望NSError* __autoreleasing *
。因此,编译器创建一个类型为NSError* __autoreleasing
的隐藏变量,在调用之前将NSError*
复制到隐藏变量中,并在调用之后将其复制回来以获得__autoreleasing的语义。
答案 1 :(得分:0)
因此,在第一行初始化后,error
是指向NSError
对象的指针。
在第一个日志中,您将记录保存指针的地址。这是& amp;的效果。运营商地址。无论如何,这就是地址被传递到doSomething方法。
你传入:指针 - >指针 - > nserror对象。
但请注意doSomething签名中的双重间接。自动释放注释使其难以发现,但其NSError **
。
因此,编译器会将您的参数和' unwraps'它两次。
它以指针开始 - >指针 - > nserror对象。然后在第一个间接后它变成指针 - > nserror对象。然后在第二个间接后它变成nserror-object。
Ergo,你正在记录两件不同的事情。第一个是指向nserror-object的指针的地址。第二个是nserror-object本身的地址。
编辑:
@MANIAK_dobrii指出error
指向的对象在前后情况下本身不同。
那是真的。如果在doSomething中发生错误,那么它会在else子句中创建一个全新的NSError实例。然后它将其加载回error
指针。这就是为什么你会看到两个不同的地址,之后error
指针完全指向另一个对象。