Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
objective-c对象中*a和**a的区别是什么?_Objective C_Pointers - Fatal编程技术网

objective-c对象中*a和**a的区别是什么?

objective-c对象中*a和**a的区别是什么?,objective-c,pointers,Objective C,Pointers,我编写以下代码: NSArray *array = @[@1, @2]; 如何输出*数组和**数组,它们之间的区别是什么?有一些答案,但我认为没有一个对您有真正的帮助,因为它们描述了技术含义。 让我们看一下第一个声明: NSArray *array …; 当有人谈论这段代码时,您会发现类似于array的语句是NSArray的实例对象。即使每一个有经验的Objective-C开发人员都知道这句话的真正含义,但这完全是错误的。正确的说法是什么 A.NSArray的实例对象 实例对象有一个状态,基

我编写以下代码:

NSArray *array = @[@1, @2];

如何输出
*数组
**数组
,它们之间的区别是什么?

有一些答案,但我认为没有一个对您有真正的帮助,因为它们描述了技术含义。 让我们看一下第一个声明:

NSArray *array …;
当有人谈论这段代码时,您会发现类似于
array
的语句是
NSArray
的实例对象。即使每一个有经验的Objective-C开发人员都知道这句话的真正含义,但这完全是错误的。正确的说法是什么

A.
NSArray的实例对象

实例对象有一个状态,基本上是一组存储的数据。为此,它需要在创建对象时保留的内存。您不直接处理这个问题,但它是在
+alloc
中完成的。这是在程序运行时显式完成的(“在堆上”、“堆分配”)

您仅通过其地址(占用内存区域的第一个内存单元的编号)对此类对象进行寻址。(每个存储单元都有一个编号,称为地址。是的,它类似于通过街道上房屋的编号来寻址房屋中的居民。因此,您可以将内存想象为一条非常非常长的街道。)

但是像
array
这样的标识符只在编译时存在,并且在编译程序时被删除。因此很明显,像
array
这样的标识符从不表示实例对象

简短版本:instane对象是内存区域,仅通过第一个内存单元(位置)的编号进行寻址

B.指向实例对象的指针(引用)

但是,如果在运行时通过实例对象的编号对其进行寻址,那么我的代码如何处理它呢?诀窍是将数字存储在变量中。(看看不完全正确的C标准。他们说它存储在一个对象中。但这些对象与Objective-C对象无关,我将重点讨论变量,一种对象的子类型。)

因此,可以使用一个变量存储实例对象的内存位置。这样的变量称为指针变量。它是用一个额外的
*
声明的。所以

NSArray * array;
表示:标识符为
数组
的指针变量,用于存储类型为
NSArray
的实例对象的位置

(地址是数字。它们是整数。因此指针变量和整数之间存在联系。您可以对这些数字进行计算,称为“指针算术”。在某些情况下,这对C开发人员很重要,但对作为Objective-C开发人员的您不重要。)

此变量的内存不是用
+alloc
显式保留的,而是在您输入声明变量的代码区域时隐式保留的。(再一次不是完全正确的,但对于这个解释来说已经足够了。)那么让我们再次看看对象创建的一个非常简化的版本:

- (void)method
{
  NSArray *array = [NSArray alloc];
}
此语句的右侧为对象实例保留内存,并返回一个数字,即内存区域的地址。此编号分配给一个名为
数组
的引用。该引用的内存(它存储某些东西,因此需要内存)通过其定义隐式保留

指向对象的指针通常称为引用

简短版本:因此
array
是对实例对象的引用,存储实例对象的地址

C.指向实例对象指针的指针

好的,我们有一个实例对象,它占用内存来存储对象状态,通过其内存位置(地址)寻址。然后我们有一个存储该地址的变量,即引用
数组
。您可以通过其标识符对其进行寻址

但有时,通过引用变量的地址来处理引用变量也是很有用的,我将在下面举一个例子。您可以使用地址运算符
&
获取变量的地址

&array
得到的是:存储实例对象地址的变量的地址。这种双重间接寻址的类型(“地址…地址…”)是

这是因为在变量定义中,
*
表示“的地址”

简短版本:指向引用的指针是存储实例对象地址的变量的地址。它是用
**
声明的。(是的,你可以有更多的间接表达……不,这不容易理解。)

D.指向引用的指针的用例

在Objective-C中通常不需要这种双重间接。但是有一个重要的用例,错误输出参数。为了理解这一点,我们将研究一个具有单个间接参数的方法,如您所知:

- (BOOL)methodThatCanProduceAnError:(NSError*)error
{
   …
   error = [NSError alloc] … // Create an error object and store its address to the reference variable error.
   return NO;
   …
}
此方法应通过其
error
参数发出错误

您可以使用如下代码“调用”这样的方法:

…
NSError *error; // A reference variable pointing to an instance object of type NSError
error = nil; // I do not have an error, so it points to "nothing".
[anInstance methodThatCanProduceAnError:error];
会发生什么?将实例对象的地址作为参数传递给该方法。你说“我没有错误”就通过了
nil
。这很清楚,因为该方法应该传递对实例对象的引用

因此,有趣的部分在方法内部,当它创建错误对象并尝试传递它时这不起作用

在Objective-C中,参数总是按值传递。这意味着,“调用代码”中的参数值将被获取并分配给“调用代码”中的新变量。这个新变量称为参数变量。当方法尝试更改变量的值时

error = [NSError alloc] … // Create an error object and store its address to the reference variable error.
它仅更改方法内变量copy的值。新引用将永远无法找到方法之外的路径,并且调用代码中的变量
error
保持不变。在“调用代码”中,
错误
…
NSError *error; // A reference variable pointing to an instance object of type NSError
error = nil; // I do not have an error, so it points to "nothing".
[anInstance methodThatCanProduceAnError:error];
error = [NSError alloc] … // Create an error object and store its address to the reference variable error.
- (BOOL)methodThatCanProduceAnError:(NSError**)error // double indirection
{
   …
   *error = [NSError alloc] … // *error is a reference to an object
   return NO;
   …
}
NSError *error; // A reference variable pointing to an instance object of type NSError
error = nil; // I do not have an error, so it points to "nothing".
NSError ** pointerToError = &error; // The address of the reference.
[anInstance methodThatCanProduceAnError:pointerToError];