Делегаты в IOS - требуется пояснение - PullRequest
10 голосов
/ 28 января 2012

Я только начинаю разработку IOS, но у меня есть несколько лет разработки ASP.net через C #. Если честно, у меня никогда не было необходимости разбираться в делегатах / событиях и т. Д., Я знаю, что использую их при программировании web.forms, но большая часть функциональности обеспечивается структурой, за кулисами. .

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

 if ([self.delegate respondsToSelector:@selector(startImporting:)])
 {
            [self.delegate startImporting:self];
 }

Правильно ли я считаю, что в псевдокоде это означает что-то вроде:

Если у метода / класса, вызывающего этот метод, есть метод с именем 'startImporting', тогда вызовите метод 'startImporting' внутри вызывающего класса.

Надеюсь, это понятно. Если это так, то по сути это будет то же самое, что иметь статический метод в C #, который вы можете вызвать с чем-то вроде:

myImportClass.startImporting();

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

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

Ответы [ 3 ]

45 голосов
/ 28 января 2012

Шаблон делегирования в Какао используется, чтобы информировать (сообщать о ходе выполнения и т. Д.) Или запрашивать (запрашивать учетные данные и т. Д.) Другой объект, не зная об этом много.

Как правило, вы используете протокол дляОпределите, какие методы вы будете вызывать для делегата, и тогда делегат должен соответствовать этому протоколу.Вы также можете добавить методы, которые делегату не нужно реализовывать (необязательно).Когда вы это сделаете, вам придется вызывать -respondsToSelector :, потому что вы не знаете, хочет ли делегат вызывать конкретный метод или нет.

Пример:
У вас есть классчто-то производит, назовем это Machine и рабочий класса Worker.Машина должна быть настроена для задачи:

Machine *machine = [[Machine alloc] init];
[machine prepareWithParameters:myParameters];

Теперь, когда у нас есть машина, мы хотим произвести огромное количество Stuff:

[machine produceStuff];

Хорошо, мысделано.Но как мы узнаем, когда была произведена единица Stuff?Мы могли бы иметь нашего работника, постоянно стоящего рядом с нашей машиной, и ждать:

while (![machine isFinished]) {
    if ([machine didProduceStuff]) {
        Stuff *stuff = [machine producedStuff];
        [self doSomethingWithStuff:stuff];
    }
    else {
        // Get a very large coffee...
    }
}

Разве не было бы здорово, если бы машина действительно сообщала нам автоматически, когда она закончила с производством единицы Stuff?

@protocol MachineDelegate <NSObject>
@optional
    - (void) machine:(Machine *)machine didProduceStuff:(Stuff *)stuff;
@end

Давайте добавим worker в качестве делегата machine:

Worker *worker;
Machine *machine = [[Machine alloc] init];
[machine prepareWithParameters:myParameters];
[machine setDelegate:worker]; // worker does conform to <MachineDelegate>

[machine produceStuff];

Когда Machine завершит создание чего-либо, он вызовет:

if ([[self delegate] respondsToSelector:@selector(machine:didProduceStuff:)])
    [[self delegate] machine:self didProduceStuff:stuff];

Затем worker получит этот метод и может что-то сделать:

- (void) machine:(Machine *)machine didProduceStuff:(Stuff *)stuff {
    [self doSomethingWithStuff:stuff];
    if ([machine isFinished])
        [self shutDownMachine:machine];

}

Разве это не намного эффективнее и проще для работника?Теперь он может сделать что-то более продуктивное, чем стоять рядом с машиной, пока машина все еще работает.Теперь вы можете добавить еще больше методов к MachineDelegate:

@protocol MachineDelegate <NSObject>
@required
    - (void) machineNeedsMaintenance:(Machine *)machine;
    - (void) machine:(Machine *)machine fatalErrorOccured:(Error *)error;
    - (BOOL) machine:(Machine *)machine shouldContinueAfterProductionError:(Error *)error;
@optional
    - (void) machineDidEnterEcoMode:(Machine *)machine;
    - (void) machine:(Machine *)machine didProduceStuff:(Stuff *)stuff;
@end

Делегаты также можно использовать для изменения поведения объекта без его подкласса:

@protocol MachineDelegate <NSObject>
@required
    - (Color *) colorForStuffBeingProducedInMachine:(Machine *)machine;
    - (BOOL) machineShouldGiftWrapStuffWhenDone:(Machine *)machine;
@end

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

1 голос
/ 28 января 2012

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

Гера - это несколько полезных ссылок в stackOverflow:

Надеюсь, это поможет

0 голосов
/ 13 июля 2013

делегаты полезны при получении обратных вызовов от другого класса

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

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

 //protocol declaration
  @protocol DownloadProtocol <NSObject>
  -(void)OnFinish;
  @end

//SOng download class
@interface songs
@property(Strong,nonatomic) id<DownloadProtcol> delegate;
-(void)Download;
@end
@implementation songs
-(void)Download
{

///the code to download goes here

[self callTheCallingClass];

}

-(void)CallTheCallingClass
{
 [self.delegate OnFinish];
}
@end

//
@interface mainclass<DownloadProtocol>

@end

@implementation mainclass

-(void)viewDidload
{
Songs *s=[[SOngs alloc]init];
s.delegate=self;
[s download];
}
-(void)OnFinish
{
  NSlog(@"Called");
}
@end
  1. см. Делегирование достигается с помощью протокола в цели c. Я думаю, что вы можете понять синтаксис этого.

  2. В классе песен мы создаем свойство для этого протокола. мы оставляем тип как ID ... потому что тип не известен во время компиляции.

  3. в классе песен, когда мы завершаем загрузку, мы называем метод протокола ...

  4. Сначала в основном классе мы принимаем синтаксис протокола учебный класс выше синтаксис этого

  5. мы создаем экземпляр класса песен

  6. затем назначить объект основного класса (self) делегату класса песен

  7. тогда мы должны применить класс протокола в .m, добавив имя метода из протокола

  8. так что теперь всякий раз, когда класс песни вызывает метод протокола через переменную экземпляра делегата .... выполняется принятие метода протокола в основном классе

попробуйте этот код, надеюсь, он поможет ...

если вы хотите больше информации по этой теме, используйте ее как шаблон дизайна делегата

главное преимущество это способствует слабосвязанному программированию ...

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