Что такое Делегирование и почему это важно в программировании на iOS?

11

В данный момент я учу себя программированию на iOS, и одной концепцией, которую мне действительно трудно обернуть, является делегирование. Что это такое? Почему и как это используется? В чем преимущество? Техническое письмо из книги, которую я читаю, затрудняет понимание.

DCIndieDev
источник
4
Может оказаться полезным целевое пересечение тегов делегатов c + при переполнении стека.

Ответы:

16

Чтобы понять delegates, ты должен понять protocols.

А protocolэто как контракт на обслуживание. Когда объект (чаще всего UIViewControllerподкласс, но не всегда) подписывает этот контракт, он говорит: «Я заинтересован в предоставлении логики для поддержки отправляемого мной сообщения». Это похоже на NSNotificationCenterотносительно подписавшись на уровне интересов, разница в том , объект , который использует делегирование может иметь только один delegateв то время, когда , как несколько объектов могут подписаться на то же самое NSNotification.

Apple использует делегирование повсеместно. Тем не менее, все больше и больше вы видите, что Apple переходит на многие из своих API blocks, которые похожи на callbacksдругие языки.

При этом делегирование помогает поддерживать MVC, хотя я бы сказал, что делегирование - это сама по себе модель проектирования. Это помогает отделить модели от контроллеров. Как в примере Джона Картрайта, a UITableViewзнает, как отображать строки и разделы. Он знает, как использовать повторно UITableViewCellsпо соображениям производительности. Он знает все другие вещи, которые UIScrollViewзнает. Но он не знает, какие клетки отображать. Он не знает, чем заполнить эти клетки. Он не знает, какие клетки повторно использовать для данного NSIndexPath. В любом случае, это действительно должна быть работа контроллера. Делегирование позволяет табличному представлению разгрузить эту логику отсутствия представления на объект, который в любом случае должен нести эту ответственность.

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

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

Но делегирование также очень полезно, когда вы хотите передавать информацию между объектами. Вы можете очень легко создавать свои собственные протоколы и подписывать свои собственные объекты, чтобы следовать им. Кроме того, методы протокола @requiredпо умолчанию, но вы можете указать некоторые методы, которые будут@optional, Это может дать вам хорошую гибкость, если вам это нужно. Допустим, у вас есть родительский контроллер представления и дочерний контроллер представления. Возможно, вы используете новый Containment API для этого. Как правило, если вам нужно передать информацию от родителя ребенку, вы делаете это с помощью свойства. Готово. Но что, если вам нужно передать информацию от ребенка обратно родителю? Может быть, что-то меняется в ребенке, и вам нужно уведомить родителя. Конечно, вы могли бы сделать некоторые КВО на определенных значениях. Но, может быть, вы хотите знать, когда кнопка нажата. Просто создайте новый протокол в контроллере дочернего представления

@protocol MyChildDelegate
- (void)buttonWasTappedInChild:(MyChildViewController *)childViewController;
@end

@interface MyChildViewController : UIViewController

@property (weak, nonatomic) id <MyChildDelegate> delegate;

@end

В MyChildViewController, когда ваша кнопка нажата, просто проверьте, отвечает ли ваш делегат на сообщение делегата (если это требуется, и ваш делегат не реализует метод, вы потерпите крах. Вы можете создать метод, @optionalесли вам нужно) и отправить Это:

- (IBAction)someButtonTapped:(id)sender {
    if ([self.delegate respondsToSelector:@selector(buttonWasTappedInChild:)]) {
        [self.delegate buttonWasTappedInChild:self];
    }
}

Затем установите делегат вашего MyChildViewController selfи внедрите его - (void)buttonWasTappedInChild:(MyChildViewController *)childViewControllerв свой родительский контроллер представления. БУМ! У вас есть информация, переданная от ребенка до родителя. Отношения между этими двумя объектами даже не должны быть такими же тесными, как родитель / ребенок. Это контракт на обслуживание, так что пока объект, подписывающий соглашение, завершает сделку, внедряя необходимые методы, вы великолепны!

ПРИМЕЧАНИЕ. Делегаты должны быть слабыми / назначать свойства, иначе вы войдете в цикл сохранения, где ни один объект не может быть освобожден.

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

jmstone
источник
2

Делегаты - это объекты, которые реализуют определенные функции, когда не имеет смысла реализовывать эти функции в обычном объекте. Это форма внедрения зависимости.

Для конкретного примера посмотрите на протокол UITableViewDelegate. Эти методы не имеют смысла для непосредственного осуществления табличного представления, потому что действия для выбора строки табличного представления будут отличаться в каждом приложении и, возможно, в каждом табличном представлении. У делегата есть метод -tableView:didSelectRowAtIndexPath:, позволяющий создать объект, который обрабатывает выбор строки, не разбивая подклассы табличного представления для каждого отдельного действия, которое вы хотите реализовать.

Джон Картрайт
источник