2009-05-04 2 views
7

Рассмотрят следующую общую ситуацию:Objective-C/Cocoa: Правильный дизайн для делегатов и контроллеров

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

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

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

Какова надлежащая конструкция для решения этой проблемы?

+0

У меня такая же проблема, как сейчас. Решение для нас ссылается. Вы говорите, что это нежелательная ситуация. Не могли бы вы объяснить, почему? – Kriem

+0

Для меня две основные причины: циркулярные ссылки «чувствуют» неправильно; вы склонны постоянно ссылаться на эту ссылку. Я могу быть полностью выключен. – Jake

+0

Я знаю, что вы имеете в виду. Я с нетерпением жду того, что другие думают об этом. Хороший вопрос. – Kriem

ответ

4

В безымянном форуме разработчиков, кто-то пишет:

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

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

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

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

+0

Мне действительно нужно посмотреть видео из Стэнфорда. – Kriem

+0

Хотя NSNotifications хорошо работают для этого случая, я настоятельно рекомендую использовать слишком много из них в вашем приложении. Уведомления очень сложны для отладки, и вы не можете просто взглянуть на свой код, чтобы увидеть, когда и где что-то увольняется. Несколько слов предупреждения. –

+0

Привет, Мэтт, я понимаю вашу озабоченность NSNotifications. В свете этого, любые другие предложения? – Jake

-1

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

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

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

+0

Но предположим, что делегат не является делегатом MainView, а каким-то другим протоколом ...? – Jake

+0

Затем используйте метод, указанный в протоколе? Он получает уведомление от MainView, не так ли? Возможно, есть какой-то важный аспект ситуации, которая отсутствует в этом вопросе. – Chuck

+0

Предположим, что я создал объект, который реализует протокол CLManagerDelegate (Cocoa Touch) и прослушивает обновления местоположения. Он не получает уведомления от MainView, но должен получить доступ к ярлыку. – Jake

0

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

При создании новых экземпляров я отношу к классу данных, как это:

[[Button alloc] initWithData:data]]; 

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

Я признаю, что он по-прежнему требует ссылок, как вы описали. Кажется, что нет простой ссылки parent.

2

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

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

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

Последнее решение в основном циклическая ссылка, но тот, который кажется мне как-то более чистым.

+0

Да, это, безусловно, самое чистое решение. – Jake

Смежные вопросы