Сохранять означает: Мне понадобится этот объект, чтобы остаться, его нельзя освобождать. Если x
не будет сохранен, вероятно, произойдет следующее:
Вы назначаете x
на foo
, поэтому foo
теперь указывает на адрес, где находится ваша NSCalendarDate. Кто-то освобождает или автоматически выпускает этот объект, его счетчик в конечном итоге падает до 0, и объект освобождается. Теперь ваш foo
по-прежнему указывает на этот адрес, но больше нет действительного объекта. Некоторое время спустя создается новый объект, и случайно он находится по тому же адресу, что и ваш старый объект NSCalendarDate. Теперь ваш foo
указывает на совершенно другой объект!
Чтобы предотвратить это, вам нужно retain
. Вы должны сказать: пожалуйста, пока не освобождайте объект, он мне нужен. Когда вы закончите с ним, вы release
это означает, что Мне больше не нужен объект, вы очистите его сейчас, если это больше никому не нужно.
Теперь о классическом задании из трех частей. Считайте, что ваш setFoo:
будет выглядеть так:
- (void) setFoo:(NSCalendarDate *)x
{
[foo release];
[x retain];
foo = x;
}
Это очень плохая идея. Предположим, что ваш объект является единственным, кто сохранил объект NSCalendarDate, и подумайте, что вы тогда сделаете: [self setFoo:foo];
. Звучит глупо, но может случиться что-то подобное. Теперь поток будет таким:
foo
будет выпущен. Его счетчик сохранности теперь может упасть до 0, и объект будет освобожден.
- Ой, мы пытаемся сохранить и получить доступ к освобожденному объекту.
Вот почему вы всегда сначала retain
новый объект, а затем release
старый объект.
Если вы работаете с фоном Java или .NET, очень важно понимать, что переменная типа Foo *
содержит только адрес вашего объекта, и ничего более. В Java или .NET переменная, которая указывает на объект, автоматически «сохраняет» его, если хотите. Не так в Objective-C (в средах без GC). Вы можете рассматривать переменную типа Foo *
как слабую ссылку, и вам явно нужно сообщить Objective-C, нужен ли вам этот объект по этому адресу или нет.