Разница между созданием локальной переменной и назначением для ivar и непосредственным назначением для ivar? - PullRequest
4 голосов
/ 06 февраля 2010

Мне всегда было интересно, почему во всех примерах кода Apple используется такой код:

UINavigationController *aNavigationController = [[UINavigationController alloc]
          initWithRootViewController:rootViewController];

self.navigationController = aNavigationController;

[self.view addSubview:[navigationController view]];

[aNavigationController release];

Они всегда создают локальную переменную и присваивают ее ivar, почему бы им просто не сделать это:

self.navigationController = [[UINavigationController alloc]
          initWithRootViewController:rootViewController];;

[self.view addSubview:[navigationController view]];

[navigationController release];

Есть ли еще какая-то причина, кроме того, что ее легче понять? Это лучшая практика?

-Oscar

Ответы [ 5 ]

2 голосов
/ 06 февраля 2010

Ваш код замены неверен и, таким образом, иллюстрирует проблему, которую Apple пытается предотвратить. Вот ваш код:

self.navigationController = [[UINavigationController alloc]
      initWithRootViewController:rootViewController];

[self.view addSubview:[navigationController view]];

[navigationController release];

Вы оставили "я". в ваших ссылках. Возможно, вы имели в виду прямой доступ к ivar, но в этом случае вы создали очень запутанный код, смешав методы доступа и прямой доступ к ivar (и нарушили основное правило, используя прямой доступ к ivar за пределами средства доступа). Если нет, то вы хотели написать это:

self.navigationController = [[UINavigationController alloc]
      initWithRootViewController:rootViewController];

[self.view addSubview:[self.navigationController view]];

[self.navigationController release];

Эта последняя строка очень неправильная. Никогда не отправлять -релиз к результату вызова метода. Так что нет, то, как ты это делаешь, неверно.

Тем не менее, Apple и я не согласны с тем, как это сделать. Вот как я это делаю:

self.navigationController = [[[UINavigationController alloc]
      initWithRootViewController:rootViewController] autorelease;

[self.view addSubview:[self.navigationController view]];

Мне нравится -autorelease, потому что я считаю, что он предотвращает ошибки. Чем дальше отделены от alloc и release, тем более вероятно, что разработчик внесет утечку памяти (например, добавив return). autorelease позволяет избежать этого, сохраняя вместе функции сохранения и освобождения, что делает намерение использовать это как временную переменную более понятным и, как правило, значительно упрощает проверку кода.

Apple имеет тенденцию не соглашаться со мной в своем примере кода, потому что они подчеркивают производительность, используя релиз по сравнению с автоматическим выпуском. Я считаю, что это неправильная оптимизация, так как этот объект не будет освобожден во время этого цикла выполнения в любом случае (поэтому память не сохраняется), и я считаю, что очень небольшое снижение производительности автоматического выпуска больше, чем восполняется уменьшение утечек памяти из-за неправильного использования релиза.

Дебаты об автоматическом выпуске и выпуске заполнены оттенками серого (я, конечно, использую выпуск непосредственно в циклах), и разные разработчики используют разные подходы, но ваш код замены не подходит для этого в любом случае.

1 голос
/ 06 февраля 2010

Обе версии пропускают проверку на нулевое значение:

(Предполагая, что self.navigationController является свойством, которое сохраняет свое значение)

self.navigationController = [[UINavigationController alloc]
    initWithRootViewController:rootViewController];
if (self.navigationController != nil) {
    [self.view addSubview: navigationController.view;
    [self.navigationController release];
}

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

1 голос
/ 06 февраля 2010

Это может быть то же самое, что и в верхнем примере, но есть вероятность, что этого не будет.

Помните, что

self.navigationController = aNavigationController;

совпадает с

[self setNavigationController:aNavigationController];

и вы не знаете, что происходит внутри этого setNavigationController метода. Это может быть инициализация другого объекта и установка его как iVar, который вы затем отпускаете, вызывая сбой.

1 голос
/ 06 февраля 2010

Различия в первых строках заключаются в том, что версия Apple разделяет создание и назначение объектов для ивара, в то время как ваша версия соединяет их вместе. Концептуально версию Apple немного легче понять. Насколько мне известно, это не лучшая практика.

0 голосов
/ 06 февраля 2010

Поскольку ясно, что в коде используется переменная экземпляра UINavigationController. Тогда не было бы никакой причины делать:

self.navigationController = aNavigationController

Если вы его не удерживаете.

Но, если вы сделаете это так:

 self.navigationController = [[UINavigationController alloc] initWithRootViewController:rootViewController];

Впоследствии, если вы отпустите это так:

[navigationController release];

Похоже, что мы выпускаем переменную экземпляра, которая должна сохраняться в течение всего времени существования текущего класса, который инициализирует контроллер навигации. Таким образом, он подвержен ошибкам, которые заставят новичков думать, что его следует выпускать только в методе dealloc.

Оба подхода будут иметь счет 0 в конце. Если при реализации dealloc:

[navigationController release]; // 1 for the ivar
[super dealloc]; // 0 for the retained subviews
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...