Может ли кто-нибудь объяснить очень просто, как работают делегаты Objective C? - PullRequest
3 голосов
/ 27 мая 2011

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

Я видел много хороших примеров и объяснений в Интернете, а также здесь, но я просто не могу его получить. Мне важно понять, почему и как, поэтому вместо использования некоторого примера из документации (кстати, я действительно отстой, когда дело доходит до понимания Apple Docs, я использую документацию php.net, с множеством примеров), потому что Я просто не понимаю этого.

Я бы хотел два класса, садовый класс. У этого есть массив с цветами, каждый цветок создан из flowerClass. Итак, flowerClass не знает, что это за сад. Иногда он просто кричит о воде.

Так что, если бы кто-то здесь мог объяснить это мне, я был бы очень благодарен!

Я попробовал, и вот я попробую, основываясь на информации, которую я получил от вас, ребята:

MyGarden.h

#import "Flower.h"

@interface MyGarden : NSObject <WateringDelegate>
{
    Flower *pinkFlower;
}
@end

MyGarden.m

#import "MyGarden.h"
#import "Flower.h"

@implementation MyGarden

- (void) giveWaterToFlower
{
    NSLog(@"Watering Flower");
}

- (void)viewDidLoad
{
    pinkFlower = [[Flower alloc] init];
    [pinkFlower setDelegate:self];
    [pinkFlower startToGrow];
}
@end

Flower.h

@protocol WateringDelegate <NSObject>
@required
- (void) giveWaterToFlower;
@end

@interface Flower : NSObject
{
    id <WateringDelegate> delegate;
}

@property (retain) id delegate;
- (void) startToGrow;
@end

Flower.m

#import "Flower.h"

@implementation Flower

@synthesize delegate;

- (void) needWater
{
    [[self delegate] giveWaterToFlower];
}

- (void) startToGrow
{
    [NSTimer scheduledTimerWithTimeInterval:10.0 target:self selector:@selector(needWater) userInfo:nil repeats:YES];
}
@end

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

Ответы [ 3 ]

4 голосов
/ 27 мая 2011

Делегат - это место, где вы реализуете пользовательское поведение для своего приложения, которое влияет на работу другого класса (например, простого старого объекта в среде Cocoa).

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

Итак, рассмотрим класс контроллера, которому принадлежит окно с некоторыми элементами управления, может быть, таблица с информацией, панель инструментов и т. Д. Вы можете установить контроллер как делегат этих элементов управления, чтобы когда элементам управления требовалось больше информации о том, что ониПредполагается, что они могут посмотреть на ваш контроллер.Возможно, вы захотите настроить способ изменения размера окна, что происходит, когда пользователь выбирает строку в табличном представлении, как отображается информация и так далее.Это все вызовы, которые элементы управления делают своему делегату (вашему контроллеру), используя методы, определенные в их протоколе делегата.Если вам повезет, вы можете написать весь свой пользовательский код без необходимости разбивать его на подклассы и разбивать их на несколько файлов.

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

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

0 голосов
/ 26 июня 2015

Когда цветок хочет воды, он стоит self.delegate giveWaterToFlower.delegate по умолчанию установлено на MyGarden, поэтому метод giveWaterToFlower в MyGarden вызывается, когда цветок хочет воды.Если вы реализовали объект wateringCan, то wateringCan может сделать [pinkFlower setDelegate:self]; Затем, когда цветок хочет воды, self.delegate giveWaterToFlower вызовет метод giveWaterToFlower в wateringCan, что может дать больше или меньше воды, чемдефолт.Аналогично, вы могли бы реализовать объект gardenHose, который также предоставляет метод giveWaterToFlower.Садовый шланг может достигать только определенного расстояния с садом, поэтому может переопределять делегата только в определенных цветах.

Но шаблон проектирования таков, что flower имеет делегированный это giveWaterToFlower методна другой объект.Объект flower понятия не имеет, кто предоставляет метод giveWaterToFlower.Вы можете включить метод giveWaterToFlower по умолчанию в flower и инициализировать ваши flower объекты с self.delegate = self;

0 голосов
/ 22 марта 2013

Шаблон делегата полезен в некоторых случаях, как показал Марк.Проблема в том, что Apple использовала их гораздо больше, чем нужно.В частности, Apple попыталась (и с треском провалилась, imo) реализовать элементарный механизм event с использованием делегатов.

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

Самая большая проблема в этом состоит в том, что у вас может быть только один обработчик делегата для события, в то время как в других языках есть много допустимых случаев, когда мы могли бы хотеть иметь несколько независимых потребителей события.Например, в C # оператор += используется для добавления обработчика события к событию объекта, что позволяет неограниченному количеству наблюдателей события.К сожалению, в Objective-C нет встроенного механизма событий, а также шаблон событий, используемый базовыми классами платформы Apple.

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

Пример того, как Apple использует делегатов для того, что на самом деле events - это метод tableView:didSelectRowAtIndexPath.Это событие.Почему должна быть разрешена зависимость только одной вещи от выбранной строки?«Решение» (хотя это скорее обходной путь) было бы для родителя, чтобы предоставить свой собственный делегат с его собственным методом делегата псевдо-события для его потомка.Но это просто означает больше работы и больше шансов на ошибку.

Примером того, как модель делегата правильно используется Apple (насколько это касается модели), является tableView:cellForRowAtIndexPathметод.Этот метод позволяет потребителю выгружать и определять поведение tableView, и не имеет смысла предоставлять более одной его реализации.

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

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

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