我正在学习如何编程,并从Objective C开始。我试图准确理解在方法中分配对象时会发生什么。
-(Fraction *) add: (Fraction *) f
{ //'result' will store the result of the addition
Fraction *result = [[Fraction alloc]init];
result.numerator = (numerator*f.denominator + denominator*f.numerator);
result.denominator = denominator*f.denominator;
[result reduce];
return result;
}
据我所知,我可以在返回时创建一个对象来存储'result',
tempStorageObject = [aFraction add: bFraction];
然后我负责释放它,但是当我不存储它时会发生什么,如:
[aFraction add: bFraction];
NSLog(@"%i/%i", result.numerator, result.denominator); //result object not declared in main
我被告知我有一个未声明的标识符。我明白了,但在使用'add'方法后,'结果'究竟发生了什么。它去哪儿了?我不应该能够访问它的变量,因为它是在方法中创建和返回的吗?显然不是,但我不明白为什么。我试过重读我的书并搜索这个论坛,但我找不到一个明确的答案。谢谢。 (第一篇文章)
答案 0 :(得分:3)
四件不同的事情:
“我明白了,但在使用'添加'方法后,'结果'究竟发生了什么。它在哪里?”
这是一个局部变量。它消失了。
“我不应该能够访问其变量”
看到你的评论,看起来你的意思是用点表示法访问。不,点符号用于属性。
“因为它已创建”
点符号不允许您访问本地变量。
“并在方法中返回?”
点符号不允许您访问函数返回值。
当他们引用对象时,前三个东西都是指针。第四件事是他们指出的。当您执行alloc时,您将在堆存储中创建一个对象。然后,您将实例变量,属性,局部变量和函数返回值引用到堆存储。在某种程度上,您认为它们与堆存储中的对象是一样的。像点符号这样的句法糖可以帮助你做到这一点。您的对象将持续,但在这种情况下,引用它的不同变量在范围上有限并且来来去去。
调用alloc时,会在堆上创建一个对象。
将结果分配给结果时,结果现在具有相同的对象。
返回结果时,局部变量结果不再存在,返回值暂时保存同一个对象,并且该对象仍然存在于堆中。
4A。当你将函数结果赋给tempStorageObject,另一个局部变量(我猜)时,函数结果就会消失。它只是暂时存在,从函数内部传递一个值到out。 tempStorageObject现在保存对象,对象仍然存在于堆中。
4b中。相反,如果你没有将函数结果赋给任何东西,那么函数结果仍然会消失。但是对象仍然存在于堆上。你有问题。堆上有一个对象,但你不能直接在那里引用它(除非你擅长猜测它的地址)。没有能够引用它,你就无法将它从堆中解脱出来,如果你一遍又一遍地做这种事情,这将是一个主要问题。堆将开始充满你无法摆脱的对象,你将耗尽内存。这就是所谓的泄漏。
在这种情况下,正确的做法是return [result autorelease]
。当你调用[something autorelease]
时,它会在“自动释放池”中添加“某些内容”,然后返回相同的内容。
您调用alloc并在堆上创建一个对象。它的保留计数从1开始。
您将其分配给结果,一个局部变量。结果有对象,它在堆上。
[result autorelease]
。结果有对象,它在自动释放池中,它在堆上。
返回。结果消失了,返回值有对象,它在自动释放池中,并且它在堆上。
5a上。将返回值分配给tempStorageObject。返回值消失了,tempStorageObject有了对象,它在自动释放池中,并且它在堆上。
6a上。您保留tempStorageObject的范围。 tempStorage对象消失了。该对象位于自动释放池中和堆上。
5b中。您不会将功能结果分配给任何内容。功能结果消失了。该对象位于自动释放池中和堆上。
7AB。自动释放池已耗尽。这通常是从系统库提供的主运行循环中的代码完成的,但是如果你知道如何,你可以自己完成。自动释放池中的所有对象(包括我们关注的对象)都会发送一条释放消息。对象的保留计数为0。
8AB。保留计数为0时,将从堆中删除该对象。该对象位于自动释放池中。
9AB。第二件事就是从池中删除所有对象。现在该对象不再存在于任何地方。
答案 1 :(得分:1)
你说你熟悉发布,所以我只是说你应该使用 autorelease 关键字,当没有更多代码块需要它时释放已分配的对象,请查看下面的文档,来自Apple:
答案 2 :(得分:1)
alloc的范围是全局的:一旦你分配了一个对象,它就有了内存空间,并且在释放计数达到零(或应用程序终止)之前,内存将保持分配状态。在此之前,该对象仍将存在。
变量的范围要短得多。在您的示例中,'result'在方法'add'的末尾超出了范围。但该变量只是一个名称,一个对象的引用。所以无论谁调用add,都应确保对返回的对象执行某些操作。否则,没有更多变量引用该对象,因此无法释放它。