Делегаты По сравнению с Уведомлениями в iPhoneOS

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

33
задан michael f golden 9 February 2010 в 21:33
поделиться

6 ответов

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

Некоторые преимущества делегирования:

  • Связь между делегирующим объектом и делегатом становится более ясной, особенно если реализация делегата является обязательной.
  • Если от делегата к делегату должно быть передано более одного типа сообщения, делегирование может сделать это более ясным, указав один метод делегата для каждого сообщения. Для уведомлений вы можете использовать несколько имен уведомлений, но все уведомления заканчиваются одним и тем же методом на стороне наблюдателя (возможно, требуется неприятный оператор switch).

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

Реализовать шаблон делегата просто:

  1. В вашем ChildViewController.h, объявите протокол делегата, который делегат должен реализовать позже:

     @protocol ChildViewControllerDelegate  
     @ optional 
     - (void) viewControllerDidChange: (ChildViewController *) controller; {{1} } @end 
     
  2. В верхней части файла создайте переменную экземпляра для хранения указателя на делегат в вашем ChildViewController:

     @protocol ChildViewControllerDelegate; 
     @ interface ChildViewController: UIViewController {
    id  делегат; 
     ... 
    } 
     @ property (assign) id  делегат; 
     ... 
     @ end 
     
  3. В RootViewController.h приведите свой класс в соответствие с протоколом делегата:

     @interface RootViewController: UIViewController  {
     ... { {1}} 
  4. В реализации RootViewController реализуйте метод делегата. Кроме того, когда вы создаете экземпляр ChildViewController, вам необходимо назначить делегата.

     @implement RootViewController 
     ... 
     // в каком-либо методе: 
    ChildViewController * controller = [[ChildViewController alloc] initWithNibName: ... 
    контроллер .delegate = self; 
     ... 
     - (void) viewControllerDidChange: (ChildViewController *) контроллер {
    NSLog (@ "Был вызван метод делегата."); {{1 }}} 
     ... 
     
  5. В реализации ChildViewController вызовите метод делегата в подходящее время:

     @implementation ChildViewController 
     ... {{1 }} // в некотором методе: 
    if ([self.delegate responseToSelector: @selector (viewControllerDidChange :)]) {
     [self.delegate viewControllerDidChange: self]; 
    } 
     ... 
     

Вот и все. (Примечание: я написал это по памяти, поэтому, вероятно, в нем есть некоторые опечатки / ошибки.)

59
ответ дан 27 November 2019 в 17:33
поделиться

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

Я всегда использую официальную декларацию протокола. На мой взгляд, это немного более логично, и это очень ясно в коде. Я предлагаю использовать UIView для изменения ваших параметров вместо контроллера. Я всегда использую один главный контроллер и имею множество подклассов UIView, которыми может управлять один контроллер. (Однако вы можете изменить следующий код для контроллера, , если вам действительно нужен контроллер вместо обычного представления.) Сделайте так, чтобы в заголовочном файле дочернего представления он выглядел так:

// ChildView.h
#import <UIKit/UIKit.h>

@protocol ChildViewDelegate; // tells the compiler that there will be a protocol definition later

@interface ChildViewController : UIView {
    id <ChildViewDelegate> delegate;
    // more stuff
}

// properties and class/instance methods

@end

@protocol ChildViewDelegate // this is the formal definition

- (void)childView:(ChildView *)c willDismissWithButtonIndex:(NSInteger)i; // change the part after (ChildView *)c to reflect the chosen options

@end

Метод между @protocol и вторым @end может быть вызван где-нибудь в реализация ChildView, и тогда ваш контроллер корневого представления может быть делегатом, который получает «уведомление».

Файл .m должен быть таким:

// ChildView.m
#import "ChildView.h"

@implementation ChildView

- (id)initWithDelegate:(id<ChildViewDelegate>)del { // make this whatever you want
    if (self = [super initWithFrame:CGRect(0, 0, 50, 50)]) { // if frame is a parameter for the init method, you can make that here, your choice
        delegate = del; // this defines what class listens to the 'notification'
    }
    return self;
}

// other methods

// example: a method that will remove the subview

- (void)dismiss {
    // tell the delegate (listener) that you're about to dismiss this view
    [delegate childView:self willDismissWithButtonIndex:3];
    [self removeFromSuperView];
}

@end

Тогда файл .h корневого контроллера представления будет включать следующий код :

// RootViewController.h
#import "ChildView.h"

@interface RootViewController : UIViewController <ChildViewDelegate> {
    // stuff
}

// stuff

@end

И файл реализации будет реализовывать метод, определенный в протоколе в ChildView.h, потому что он будет запускаться, когда ChildView требует его запуска. В этом методе поместите то, что происходит, когда вы получите уведомление.

2
ответ дан 27 November 2019 в 17:33
поделиться

Как насчет

return i > j? (i > k? i: k): (j > k? j: k);

двух сравнений, без использования временных временных переменных стека...

-121--3506949-

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

-121--4144520-

В этом случае нет необходимости использовать делегирование или уведомление, поскольку нет необходимости напрямую обмениваться мнениями. Как сказал gerry3, необходимо изменить саму модель данных, а затем позволить всем остальным представлениям отреагировать на это изменение.

Модель данных должна быть независимым объектом, к которому имеют доступ все контроллеры представлений. (Ленивый способ - парковать его как атрибут делегата приложения.) Когда пользователь вносит изменения в ракурс A, контроллер ракурса A записывает эти изменения в модель данных. Затем при каждом открытии ракурсов B-Z их контроллеры считывают модель данных и соответствующим образом конфигурируют ракурсы.

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

0
ответ дан 27 November 2019 в 17:33
поделиться

Действительно ли необходимо, чтобы контроллер корневого представления знал об изменениях, или только вложенные представления?

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

0
ответ дан 27 November 2019 в 17:33
поделиться

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

Я считаю делегирование более формальным и мне нравится различие, которым недавно поделился Питер Хоси:

Разница в том, что делегирование является для одного (и двунаправленного) коммуникации, в то время как уведомления предназначены для многих, однонаправленных коммуникации.

Кроме того, я обнаружил, что (полное) обновление представления в viewWillAppear: работает нормально (но это не лучшее решение, если речь идет о производительности).

12
ответ дан 27 November 2019 в 17:33
поделиться

Я хотел бы добавить:

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

25
ответ дан 27 November 2019 в 17:33
поделиться
Другие вопросы по тегам:

Похожие вопросы: