Objective-C / Какао: правильный дизайн для делегатов и контролеров - PullRequest
7 голосов
/ 04 мая 2009

Рассмотрим следующую общую ситуацию:

В вашем приложении Какао есть некоторые MainView, загруженные из NIB, который контролируется MainViewController. Ваш MainView содержит некоторые элементы управления, такие как UILabel infoLabel. У вас также есть класс делегата MyDelegate, который получает какое-то событие.

Вы хотели бы убедиться, что когда MyDelegate получает свое событие, infoLabel обновляется соответствующим образом. Однако проблема в том, что MyDelegate не имеет ссылки на MainView или MainViewController и не знает о метке.

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

Каков правильный дизайн для решения этой проблемы?

Ответы [ 4 ]

4 голосов
/ 04 мая 2009

На неназванном форуме разработчиков кто-то пишет:

Итак, короче говоря, я решил, что начну использовать NSNotifications. Стэнфордский онлайн-курс, которым следуют люди, преподают два инженера Apple. Только что они недвусмысленно заявили, что НЕ должны использовать делегат приложения или глобальные переменные, и сказали, что они должны использовать NSNotifications, делегаты и наблюдения K-V.

Если это то, что говорят инженеры Apple, я собираюсь двигаться в этом направлении.

NSNotifications довольно изобретательны в том смысле, что они не слишком сильно мешают инкапсуляции. Слушатель слушает только уведомление и объект - я не думаю, что он должен знать или заботиться о том, кто его отправил.

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

2 голосов
/ 04 мая 2009

Вот 2 варианта, которые приходят на ум:

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

  • Вы также можете привязать значение infoLabel к некоторому ключу (используя, например, привязки Какао или просто необработанное наблюдение значения ключа). Связанный объект (который может быть делегатом или каким-либо другим объектом модели) может просто обновить связанный ключ, что приведет к передаче значения в infoLabel. Например, вы можете привязать член info к значению infoLabel. Когда делегат получает событие, он может обновить информационный элемент, и представление изменится. Само фактическое связывание может происходить в IB (если ваш делегат находится в кончике) или в контроллере (который имеет ссылку на представление и делегат.)

Последнее решение - в основном круговая ссылка, но мне оно кажется чище.

0 голосов
/ 04 мая 2009

Мы реализовали сложный объект «Данные», который управляет практически всем. Он проверяет, есть ли изменения, и обновляет все глобальные переменные.

При создании новых экземпляров я ссылаюсь на класс Data следующим образом:

[[Button alloc] initWithData:data]];

Где data - класс данных сингелтона. Теперь мы можем проверить, есть ли изменения, необходимые для реагирования.

Я признаю, это все еще требует ссылок, как вы описали, хотя. Кажется, здесь нет простой ссылки parent.

0 голосов
/ 04 мая 2009

Обычный шаблон, как вы сказали, передает указатель на MainView через его методы делегата. Итак, если MainView вызывает метод своего делегата doSomethingWithFoo:, вы хотите изменить этот метод на:

- (void)mainView:(MainView *)view doSomethingWithFoo:(id)foo

и соответственно вызовите новый метод. Если вы работаете непосредственно с указателем MainView, у вас не должно возникнуть проблем с циклическими ссылками.

...