当您将参数传递给方法时,它会被复制,然后在您的方法中处理该副本:
- (void)changeA:(NSInteger)aToChange {
aToChange = 7;
}
然后,当您使用该方法时,您将无法更改从该方法内部传递的值:
NSInteger a = 42;
[smb changeA:a];
// a is still 42
那是因为在 -changeA: 内部你处理了一个参数的副本,也就是说,你做了类似(伪代码)这样的事情:
// inside changeA:
NSInteger aToChange = a; // (value is copied)
aToChange = 7; // this does not modify a, right?
你甚至可以得到aToChange 的地址并尝试用它做点什么:
// inside changeA:
NSInteger aToChange = a; // (value is copied)
NSInteger *pointerToCOPY = &aToChange; // get address of aToChange
NSInteger *pointerToA = &a; // get address of a
// here pointerToCOPY != pointerToA
所以,回到你的代码:
NSError *error = nil; // outer error, passed as a parameter
...
- (id)doSomethingWithObj:(NSObject *)obj error:(NSError *)error
{
// NSError *error(local copy) = error(passed argument);
error = tmp; // here error is the pointer to the local error copy
return nil;
}
与之前的aToChange 一样,您无法从方法内部修改外部NSError error *。这就是使用双指针的原因,您将指针发送到您的指针,这样您仍然可以访问外部 error 引用并可以设置它。
- (id)doSomethingWithObj:(NSObject *)obj error:(NSError **)error
{
// NSError **error(local copy) = error(passed argument);
*error = tmp; // Here *error is the pointer to the local error copy,
// When you dereference error you get NSError *, which you can set,
// that's your external error.
return nil;
}
请注意,这样做是不可能的:
NSError *error = nil;
NSError *otherError = [NSError error with];
*error = otherError;
error 是一个指向结构体的指针,*error 是一个结构体,具有单个 isa 字段的结构体(从 id 类型定义的角度来看)。将指向错误的指针(otherError,即平台指针大小 int)分配给结构是不合适的。
然后,最后一个问题仍然存在,你为什么不能:
NSError *error = nil;
NSError *otherError = [NSError error with];
*error = *otherError; // why can't I assign to structs?
我不完全确定,但是,也许内存管理和 ABI 出现在游戏中,在这里它可以将一堆字节从一个对象复制到另一个对象,因为它们只是一个 C 结构。
如您所知,Objective-C 是 C 的超集,可以在那里分配结构:Assign one struct to another in C。我认为这是处理对象的 Objective-C 特性。一切都是动态的,您可以在运行时创建类并添加实例变量(Mike Ash on that topic),因此在编译时不知道结构中的isa 字段之外的内容,实际上id 是只是一个带有单个isa 的指向该结构的指针。仅仅复制单个 isa 结构并说你完成了,这不是一个好主意,事情会分崩离析。