Objective-C, выпуская объект два раза? - PullRequest
0 голосов
/ 03 апреля 2011

Я недавно начал изучать 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;
}

Меня интересует сумма и сумма2. Вот метод добавления:

- (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, что означает, что объект "в" sum2 сейчас "в" sum, а sum2 не занимает никакой памяти после присваивания , Затем новый resultFraction выделяется и возвращается в sum2, который свободен до сих пор и т. Д., Пока сумма не будет освобождена после выхода из цикла.

Теперь есть только один объект (тот, который возвращается add:), и он просто присваивается sum / sum2 (указатели? Или?). Тем не менее, это не то, что я думал, что - когда sum2 назначается новый объект (объект, возвращенный add:), и не освобождается, даже после назначения этого объекта sum, предыдущий один все еще там. Это означает, что после n назначений будет n объектов "in" sum2. и из-за этого, когда я пытаюсь освободить и sum и sum2 до истощения пула, я получаю ошибку. Ошибка от второго объекта, который я пытаюсь освободить, и я просто могу выпустить или sum или sum2, потому что они оба связаны с последним объектом, возвращенным методом add:?

Надеюсь, я был достаточно ясен, потому что весь день бился головой о стену, и это просто пришло ко мне, и я действительно надеюсь, что понял это правильно, чтобы я мог продолжить читать книгу. :)

1 Ответ

2 голосов
/ 03 апреля 2011

Что это за книга?Это некоторые явно нестандартные шаблоны управления памятью.

Во-первых, этот метод:

- (Fraction *) add: (Fraction *) f

Должен возвращать автоматически освобожденный объект.В настоящее время это не так.Это приводит к массовой путанице на вызывающей стороне в том, что мантра больше не «если вы хотите сохранить возвращаемое значение объекта (за пределами NARC), вы должны сохранить его».

Далее, когда вы видите выражениекак sum = sum2; (где обе переменные являются ссылками на объекты; Foo *), то есть точно как выражение x = 5;.Это простое числовое задание;нет сохранения / освобождения подразумевается.

Чт, если у вас есть:

sum = [[Fraction alloc] init];
sum2 = [[Fraction alloc] init];
sum = sum2;

Вы только что слили экземпляр Fraction, на который ссылался sum2.Итак:

  • воспринимает удержания / высвобождения как дельты;Вы увеличиваете или уменьшаете количество.Пока ваши увеличения точно сбалансированы с вашими уменьшениями, вы делаете это правильно.

  • воспринимайте sum в Fraction *sum; как потенциальную ссылку на объект.Когда объявлено, это ничего.Когда вы присваиваете результат [[Fraction alloc] init];, волшебства нет - sum просто хранит адрес объекта Fraction в памяти.

Вы имеете в виду это?

    sum2 = [sum add: aFraction];
    [sum release];
    sum = sum2;

* * release освобождает старый sum перед тем, как перезаписать этот указатель ссылкой на новый объект в следующей строке.

Попробуйте построить и проанализировать этот код.Это будет выдавать предупреждения.Книга научит вас, как управлять памятью, используя шаблон, который не течет, но, безусловно, не является стандартным.Я не уверен, что идти по этому пути полезно;Реальность такова, что у вас будет всегда с автоматическим выпуском в игру и, следовательно, вы должны всегда следовать стандартам системы, даже в вашем собственном полностью изолированном коде.Зачем тратить время на изучение, а затем на обучение другой модели в этой точке?(Я весь для изучения различных шаблонов и систем ... просто не в этом контексте).

...