Подтвердить что ты не робот

Делегаты Vs. Уведомления в iPhoneOS

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

4b9b3361

Ответ 1

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

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

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

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

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

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

    @protocol ChildViewControllerDelegate <NSObject>
    @optional
    - (void)viewControllerDidChange:(ChildViewController *)controller;
    @end
    
  • В верхней части файла создайте переменную экземпляра, чтобы удерживать указатель на делегат в вашем ChildViewController:

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

    @interface RootViewController : UIViewController <ChildViewControllerDelegate> {
    ...
    
  • В реализации RootViewController реализуем метод делегата. Кроме того, при создании экземпляра ChildViewController вам необходимо назначить делегат.

    @implement RootViewController
    ...
    // in some method:
    ChildViewController *controller = [[ChildViewController alloc] initWithNibName:...
    controller.delegate = self;
    ...
    - (void)viewControllerDidChange:(ChildViewController *)controller {
        NSLog(@"Delegate method was called.");
    }
    ...
    
  • В реализации ChildViewController вызовите метод делегата в соответствующее время:

    @implementation ChildViewController
    ...
    // in some method:
    if ([self.delegate respondsToSelector:@selector(viewControllerDidChange:)]) {
        [self.delegate viewControllerDidChange:self];
    }
    ...
    

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

Ответ 2

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

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

Ответ 3

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

Я считаю делегацию немного более формальной и похожей на то, что недавно Peter Hosey поделился недавно:

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

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

Ответ 4

Уведомления могут значительно усложнить поведение вашей программы во время выполнения. Подумайте об этом как о переходе с несколькими пунктами назначения. Порядок этих назначений не определен. Если вы когда-либо сталкивались с сбоем, информация о трассировке нескольких файлов отсутствует.

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

Стоит изучить шаблон делегата в iOS. Делегаты дают вам полные следы стека при отладке. Они приводят к значительно более простому исполнению во время работы, все еще достигая цели развязки ваших объектов.

Ответ 5

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

Я всегда использую объявление формального протокола. Это немного логично в моем сознании, и это очень ясно в коде. Я предлагаю использовать UIView для изменения ваших параметров вместо контроллера. Я всегда использую один главный контроллер и имею много подкласса UIViews, которые может контролировать один контроллер. (Тем не менее, вы можете изменить следующий код для контроллера, , если вам действительно нужен контроллер вместо обычного view.) В файле заголовка дочернего представления сделайте так:

// 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 требует его запуска. В этом методе поместите материал, который будет происходить, когда вы получите уведомление.

Ответ 6

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

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

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

Ответ 7

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

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