我最近开始学习Objective-C 2.0,有一本书,我想知道我是否有这个概念。
所以这里是代码,它会导致释放未分配对象的错误:
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
Fraction *aFraction = [[Fraction alloc] init];
Fraction *sum = [[Fraction alloc] init], *sum2;
int n, i, pow2;
[sum setTo: 0 over: 1];
NSLog (@"Enter a value for n");
scanf ("%i", &n);
pow2 = 2;
for ( i = 1; i <= n; ++i ) {
[aFraction setTo: 1 over: pow2];
sum2 = [sum add: aFraction];
[sum release];
sum = sum2;
pow2 *= 2;
}
NSLog (@"After %i iterations, the sum is %g and the fraction is %i/%i.", n, [sum convertToNum], [sum numerator], sum.denominator);
[aFraction release];
[sum release];
[pool drain];
return 0;
}
我想知道sum和sum2。这是方法add:
- (Fraction *) add: (Fraction *) f
{
Fraction *resultFraction = [[Fraction alloc] init];
int resultNum, resultDenom;
resultNum = numerator * f.denominator + denominator * f.numerator;
resultDenom = denominator * f.denominator;
[resultFraction setTo: resultNum over: resultDenom];
[resultFraction reduce];
return resultFraction;
}
让我解释一下我的想法。
对于循环的第一次迭代,分配sum
,然后输入add:
方法,并分配resultFraction
。它返回sum2
,这意味着resultFraction在返回后不会占用任何内存。
在循环之前分配的第一个总和将被释放sum = sum2
,这意味着“{1}}中的对象现在”在“{1}}中,sum2
在完成任务后没有任何记忆。接下来,分配一个新的sum
并返回到sum2
,直到现在这是免费的,依此类推,直到退出循环后释放sum。
现在只有一个对象(由resultFraction
返回的对象),它只被分配给sum2
/ add:
(指针?或?)。但是,它不像我想的那样 - 当sum
被分配一个新对象(由sum2
返回的对象)并且没有被释放时,即使在将该对象分配给{{ 1}},前一个仍在那里。这意味着在n个赋值之后,将有n个对象“在”sum2
中。因此,当我尝试在池排放之前释放add:
和sum
时,我得到了错误。错误来自我尝试发布的第二个对象,我只能释放 sum2
或sum
,因为它们都连接到{返回的最后一个对象{1}}方法?
我希望我足够清楚,因为我整天都在撞墙,而且它刚刚来到我身边,我真的希望我能做到这一点,所以我可以继续读这本书。 :)
答案 0 :(得分:2)
首先,这个方法:
- (Fraction *) add: (Fraction *) f
应该返回一个自动释放的对象。目前不是。这导致调用方面的大量混淆,因为咒语不再是“如果你想保持一个对象返回值(超出NARC),你必须保留它”。
接下来,当您看到类似sum = sum2;
的表达式(其中两个变量都是对象引用; Foo *)时,完全就像表达式x = 5;
一样。这是一个简单的数字赋值;没有保留/释放暗示。
周四,如果你有:
sum = [[Fraction alloc] init];
sum2 = [[Fraction alloc] init];
sum = sum2;
你刚刚泄露了sum2所指的Fraction实例。所以:
将保留/释放视为增量;你增加或减少计数。只要你的增加与你的减少完全平衡,你就是这样做的。
将sum
中的Fraction *sum;
视为对象的潜在引用。宣布时,它什么都没有。当您将其分配给[[Fraction alloc] init];
的结果时,没有魔法 - sum
只保留内存中Fraction对象的地址。
你指的是这个吗?
sum2 = [sum add: aFraction];
[sum release];
sum = sum2;
release
释放旧sum
,然后通过引用下一行的新对象覆盖该指针。
尝试构建并分析该代码。它会产生警告。这本书教你如何使用不泄漏的模式进行内存管理,但绝对不是标准的。我不相信沿着这条路走下去是有用的;现实情况是,总是在游戏中自动释放,因此,总是遵循系统的标准,即使是在你自己完全孤立的代码中也是如此。为什么花时间学习,然后不学习,在这一点上有不同的模式? (我全都是为了学习不同的模式和系统......只是不在这种情况下)。