Правильный способ размещения / инициализации переменных экземпляра в Objective-C? - PullRequest
3 голосов
/ 12 июня 2009

Я просматривал пример кода в превосходном блоге Джеффа Ламарша , когда наткнулся на следующее:

- (void)applicationDidFinishLaunching:(UIApplication*)application
{
    CGRect rect = [[UIScreen mainScreen] bounds];

    window = [[UIWindow alloc] initWithFrame:rect];

    GLViewController *theController = [[GLViewController alloc] init];
    self.controller = theController;
    [theController release];

    // ...
}

В .h мы видим, что "window" и "controller" - это ivars, объявленные так:

@interface OpenGLTestAppDelegate : NSObject 
{
    UIWindow            *window;
    GLViewController    *controller;
}
@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet GLViewController *controller;
@end

Мой вопрос: почему «окно» и «контроллер» назначаются по-разному?

Мне кажется, я понимаю, почему каждый вид назначения работает (отслеживая счет удержания), но почему они назначаются по-разному? В частности, почему контроллер не назначается таким же образом, как окно с одной линией, как это, без прохождения через установщик:

    controller = [[GLViewController alloc] init];

В общем, когда вы будете использовать метод с одной строкой и когда вы будете использовать метод с несколькими строками?

Спасибо.

Ответы [ 3 ]

3 голосов
/ 12 июня 2009

Создает ли он пользовательский установщик для переменной экземпляра controller?

Если это так, может существовать код, который вызывается при изменении переменной controller через установщик. Просто установите переменную controller с помощью:

controller = [[GLViewController alloc] init];

не будет вызывать метод установки; однако, присваивая недавно выделенный объект локальной переменной, затем устанавливая его с помощью:

self.controller = theController;

вызовет метод установки, поскольку это сокращенный способ записи:

[self setController:theController];

и дополнительный код в установщике будет выполнен. Это обычно, где вы ожидали бы различие между двумя методами.

Edit:

Очевидно, что после просмотра кода он не реализует пользовательский метод установки, однако метод, который он использовал , по-прежнему наиболее часто используется, когда будет реализован метод пользовательского установки.

Я предполагаю, что причина дополнительного кода заключается в том, что он планирует выпустить переменную после выделения, и, если она назначена локальной переменной, он может вызвать метод setter с локальной переменной и затем вызвать release для локальная переменная впоследствии. Это было бы в целом более читабельным, чем использование

[[self controller] release]

Тем не менее, это странный способ сделать это, так как синтезированная реализация установщика сохранит переменную экземпляра, но затем он освобождает ее, как только она была установлена ​​в переменную экземпляра, а вызов release отменяет Для вызова retain было бы более разумно установить переменную, используя однострочный метод.

2 голосов
/ 13 июня 2009

Как указал Куинн, присвоение контроллеру ivar может быть записано в одну строку с использованием метода autorelease. Причина использования более подробной версии именно для того, чтобы избежать автоматического выпуска и использовать вместо этого ручной выпуск. Это связано с рекомендацией Apple минимизировать использование пулов авто-релизов на iPhone. Таким образом, вы должны сохранить ссылку на вновь выделенный объект в локальной переменной, чтобы освободить ее после обращения к сеттеру.

Рассматривая вопрос, когда использовать прямое присвоение переменной экземпляра (как в случае window ivar), а когда использовать метод установки (как в случае controller ivar), это в основном вопрос стиля, но вам лучше быть последовательным.

Существует два стиля настройки ивара:

  1. Всегда используйте прямое назначение ивару. Переключайтесь на методы сеттера только для иваров, для которых сеттер должен выполнить некоторую дополнительную работу помимо назначения.
  2. Всегда используйте методы установки для всех ivars.

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

Только что нашел хорошее обсуждение проблемы в другом потоке: Имена переменных экземпляра / аргумента метода в Objective C .

2 голосов
/ 12 июня 2009

Дополнительный код, кажется, только потому, что он специально хочет использовать свойство (метод установки). В его реализации (GLView.m) -setController также устанавливает логический ivar на основе того, отвечает ли контроллер (реализует) метод -setupView:.

Несмотря на это, может показаться, что однострочное решение будет работать так же хорошо:

self.controller = [[[GLViewController alloc] init] autorelease];

Также работает та же строка, что и при явной отправке сообщения (без точечного синтаксиса):

[self setController:[[[GLViewController alloc] init] autorelease]];

Любой из подходов оставит новый контроллер с правильным счетом сохранения и при этом все равно будет использовать свойство setter.

(Примечание: рассматриваемый код связан в конце этого сообщения в блоге .)


Edit:

Извините за путаницу. Код имеет ivar «GLViewController * controller» и свойство как в ___PROJECTNAMEASIDENTIFIER___AppDelegate.m, так и GLView.m, и я смотрел на последнее. (В первом случае сеттер действительно синтезирован, и он сохранит контроллер. В строках 77-81 вы можете увидеть код, который я упоминал, и он фактически не сохраняет контроллер - только AppDelegate сохраняет его.)

В коде делегата приложения синтезированный установщик сохранит GLViewController, поэтому мой совет по замене одной строки остается в силе. О читабельности можно поспорить обоими способами, но для тех, кто хорошо понимает иероглиф сохраняемого выпуска, я бы предположил, что однострочная версия гораздо более читабельна. Он кратко сообщает намерение и даже дает неявный намек на то, что установщик сохранит контроллер. Локальная переменная на самом деле просто ненужный пух.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...