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

时间:2016-08-19 11:09:02

标签: ios objective-c pointers nserror

即使我已阅读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实例?

2 个答案:

答案 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指针完全指向另一个对象。