Делегаты являются полезным инструментом в общении между объектами. В этом уроке мы создадим и реализуем пользовательский делегат, который позволит трем UISliders настроить цвет фона ViewController .
О делегатах
Сообщения в Objective-C — это улица с односторонним движением. Родительский класс может отправить сообщение своему дочернему элементу, но дочерний элемент не может самостоятельно отправить сообщение своему родительскому элементу. Однако с помощью делегата можно установить двустороннюю связь. UIScrollView и UITableView регулярно используют делегатов для связи между моделью, представлением и контроллером. Есть много причин, по которым шаблон делегата полезен. Делегат может использоваться для многократного использования объекта, для предоставления гибкого способа отправки сообщений или для реализации настройки.
Шаг 1: Создайте новый проект
Запустите Xcode и нажмите «Файл»> «Создать»> «Проект». Выберите приложение iOS Single View и нажмите «Далее». Назовите свой продукт «Делегаты» и введите имя для своего идентификатора компании, например «com.companyName.delegates». Выберите семейство устройств iPhone и нажмите «Далее». Выберите место для хранения вашего проекта и нажмите «Создать».

Шаг 2: UISlider подклассов UISlider
Нажмите Файл> Создать> Файл и выберите класс Cocoa Touch Objective-C. Назовите свой класс «MTSlider» и выберите UISlider из выпадающего меню «Подкласс». Нажмите «Далее», затем нажмите «Создать».

Шаг 3: Добавление методов протокола делегата
Сначала нам нужно объявить методы для делегата. Нажмите на «MTSlider.h.» Введите следующий код над интерфейсом.
|
1
2
3
4
5
6
7
|
@class MTSlider;
@protocol MTSliderDelegate <NSObject>
@optional
— (void)MTSliderDidChange:(MTSlider *)MTSlider withValue:(CGFloat)value;
@required
— (CGFloat)startPositionForMTSlider:(MTSlider *)MTSlider;
@end
|
Директива компилятора
Обратите внимание на строку @class MTSlider . Размещая этот код над всем остальным, компилятору сообщают, что в какой-то момент в MTSlider будет объявлен MTSlider . Без этой директивы компилятора компилятор выдаст вам предупреждение, потому что он ожидает найти интерфейс для MTSlider прямо сейчас.
Объявление методов делегата
Методы делегата объявляются начиная с @protocol . Протокол MTSliderDelegate соответствует протоколу MTSliderDelegate по определенной причине. Протокол NSObject содержит метод respondsToSelector: который можно использовать для гарантии того, что объект делегата фактически реализует необязательный метод перед вызовом метода. Вызов метода, который не реализован объектом делегата, приведет к сбою приложения.
Дополнительный метод
Проще говоря, необязательный метод — это метод, который не должен быть реализован объектом делегата; в этом случае объектом делегата будет ViewController , однако это может быть любой объект. Необязательный метод MTSliderDidChange:withValue: в объекте делегата при изменении значения ползунка.
Обязательный метод
С другой стороны, обязательный метод — это метод, который должен быть реализован объектом делегата, иначе вы получите предупреждение компилятора. Обязательный метод startPositionForMTSlider: запрашивает объект делегата, с которого должны начинаться ползунки, и получает значение его начальной позиции в ответ от делегата.
Создание переменной экземпляра для делегата
Еще в «MTSlider.h» введите следующий код непосредственно под @interface чтобы объявить переменную экземпляра, или ivar, для делегата.
|
1
|
id <MTSliderDelegate> sliderDelegate;
|
Если вы используете ARC, введите следующий код:
|
1
|
__weak id <MTSliderDelegate> sliderDelegate;
|
Ivar имеет тип id поэтому он гибкий и может принимать любой тип объекта. В следующей части MTSliderDelegate говорится, что любой объект, в конечном итоге назначаемый sliderDelegate будет содержать методы протокола MTSliderDelegate как часть его собственной реализации.
Создание сеттеров и геттеров
Закончите, синтезируя методы сеттера и геттера. Введите следующий код чуть ниже закрывающей скобки переменной экземпляра.
|
1
|
@property (nonatomic, assign) id <MTSliderDelegate> sliderDelegate;
|
Если вы используете ARC, введите следующий код:
|
1
|
@property (nonatomic, weak) id <MTSliderDelegate> sliderDelegate;
|
Нажмите «MTSlider.m» и введите следующий код чуть ниже @implementation чтобы завершить свойство.
|
1
|
@synthesize sliderDelegate;
|
Шаг 4: Соответствие методам протокола делегата
Нажмите на файл «ViewController.h». Введите следующий код для соответствия протоколу MTSliderDelegate и импортируйте «MTSlider.h».
|
1
2
|
#import «MTSlider.h»
@interface ViewController : UIViewController <MTSliderDelegate>
|
Реализация методов протокола делегата
Нажмите на файл «ViewController.m» и введите следующий код для реализации MTSliderDelegate протокола MTSliderDelegate .
|
1
2
3
4
5
6
7
|
— (CGFloat)startPositionForMTSlider:(MTSlider *)MTSlider{
}
— (void)MTSliderDidChange:(MTSlider *)MTSlider withValue:(CGFloat)value{
}
|
Шаг 5: Настройка делегата
Пользовательский инициализатор
Создание пользовательского инициализатора является ключом к получению начальной позиции для ползунков. В «MTSlider.h» добавьте следующий код, чтобы объявить новый инициализатор.
|
1
|
— (id)initWithFrame:(CGRect)frame andDelegate:(id<MTSliderDelegate>)delegateObject;
|
Нажмите «MTSlider.m» и найдите метод initWithFrame: . Удалите существующий метод и замените его следующим кодом.
|
1
2
3
4
5
6
7
8
|
— (id)initWithFrame:(CGRect)frame andDelegate:(id<MTSliderDelegate>)delegateObject{
self = [super initWithFrame:frame];
if (self) {
self.sliderDelegate = delegateObject;
self.value = [sliderDelegate startPositionForMTSlider:self];
}
return self;
}
|
Установка делегата во время инициализации позволяет немедленно вызвать метод делегата. Метод startPositionForMTSlider: получает начальную позицию для ползунков. Поскольку он вызывается в инициализаторе, позиции ползунков устанавливаются до их отрисовки на экране.
Переопределение метода UISlider
Метод UISlider setValue:animated: вызывается автоматически при каждом перемещении колышка ползунка. В файле «MTSlider.m» добавьте следующий метод.
|
1
2
3
4
5
6
|
— (void)setValue:(float)value animated:(BOOL)animated{
[super setValue:value animated:animated];
if (sliderDelegate != nil && [sliderDelegate respondsToSelector:@selector(MTSliderDidChange:withValue:)]){
[[self sliderDelegate] MTSliderDidChange:self withValue:value];
}
}
|
При переопределении setValue:animated: каждый раз, когда перемещается ползунок, сообщение отправляется объекту делегата. Обратите внимание на вызов супер, super setValue:animated: Важно, чтобы мы случайно не испортили что-то, что метод делает за кадром при переопределении существующего метода.
Метод делегата MTSliderDidChange:withValue: это необязательный метод протокола, объявленный ранее. Объект делегата передается каждый раз при смене слайдера. Помните, что вызов метода, который не был реализован, приведет к сбою приложения. Вызов respondsToSelector: на объекте делегата проверяет, можно ли идти вперед и сообщать необязательный метод делегата.
Шаг 6: установка цвета фона и создание слайдеров
Нажмите на файл «ViewController.m» и введите следующий код внутри viewDidLoad чтобы установить цвет фона представления с четырьмя компонентами цвета и создать красный, зеленый и синий объекты MTSlider . Если вы используете ARC, обязательно удалите строки [redSlider release]; , [greenSlider release]; и [blueSlider release]; так как эти звонки не нужны.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
CGFloat sliderColorPosition = 0.3f;
self.view.backgroundColor = [UIColor colorWithRed:sliderColorPosition green:sliderColorPosition blue:sliderColorPosition alpha:1.0f];
CGRect redSliderFrame = CGRectMake(20.0f, 20.0f, 280.0f, 28.0f);
MTSlider *redSlider = [[MTSlider alloc] initWithFrame:redSliderFrame andDelegate:self];
redSlider.tag = 1;
[self.view addSubview:redSlider];
[redSlider release];
CGRect greenSliderFrame = CGRectMake(20.0f, 70.0f, 280.0f, 28.0f);
MTSlider *greenSlider = [[MTSlider alloc] initWithFrame:greenSliderFrame andDelegate:self];
greenSlider.tag = 2;
[self.view addSubview:greenSlider];
[greenSlider release];
CGRect blueSliderFrame = CGRectMake(20.0f, 120.0f, 280.0f, 28.0f);
MTSlider *blueSlider = [[MTSlider alloc] initWithFrame:blueSliderFrame andDelegate:self];
blueSlider.tag = 3;
[self.view addSubview:blueSlider];
[blueSlider release];
|
Используя пользовательский инициализатор MTSlider , initWithFrame:andDelegate: делегат устанавливается, и объект ViewController становится объектом делегата каждого ползунка. Обычно вы можете ожидать увидеть набор делегатов, используя следующий код: redSlider.sliderDelegate=self; , Однако в этом случае назначение делегата передается во время инициализации.
Обратите внимание, что свойство тега каждого слайдера установлено. Первоначально цвет фона ViewController установлен на темно-серый. При настройке каждого ползунка цвет фона будет меняться соответственно, поскольку тег определяет, какой ползунок активен.
Шаг 7: Изменение цвета фона
Найдите реализацию startPositionForMTSlider: и введите следующий код внутри фигурных скобок, чтобы установить начальное значение ползунков на 0,3.
|
1
2
|
CGFloat sliderStartPosition = 0.3f;
return sliderStartPosition;
|
Регулировка цвета фона
Найдите реализацию MTSliderDidChange:withValue: и добавьте следующий код для настройки цвета фона.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
if (MTSlider.tag == 1) { //Red Slider
CGColorRef bgColor = self.view.backgroundColor.CGColor;
const CGFloat *colorsPointer = CGColorGetComponents(bgColor);
CGFloat currentGreen = colorsPointer[1];
CGFloat currentBlue = colorsPointer[2];
self.view.backgroundColor = [UIColor colorWithRed:value green:currentGreen blue:currentBlue alpha:1.0f];
}
if (MTSlider.tag == 2) { //Green Slider
CGColorRef bgColor = self.view.backgroundColor.CGColor;
const CGFloat *colorsPointer = CGColorGetComponents(bgColor);
CGFloat currentRed = colorsPointer[0];
CGFloat currentBlue = colorsPointer[2];
self.view.backgroundColor = [UIColor colorWithRed:currentRed green:value blue:currentBlue alpha:1.0f];
}
if (MTSlider.tag == 3) { //Blue Slider
CGColorRef bgColor = self.view.backgroundColor.CGColor;
const CGFloat *colorsPointer = CGColorGetComponents(bgColor);
CGFloat currentRed = colorsPointer[0];
CGFloat currentGreen = colorsPointer[1];
self.view.backgroundColor = [UIColor colorWithRed:currentRed green:currentGreen blue:value alpha:1.0f];
}
|
Каждый раз, когда изменяется ползунок, в метод делегата отправляется сообщение. Сообщение содержит текущий MTSlider и его значение. Доступ к свойству тега текущего слайдера позволяет определить, какой слайдер отправил сообщение, и цвет фона соответствующим образом обновляется.
Шаг 8: Тестирование делегата
Выберите «Продукт»> «Выполнить» или нажмите стрелку «Выполнить» в верхнем левом углу, чтобы просмотреть ползунки в действии. Настройте ползунки, чтобы увидеть, как дочерние элементы могут контролировать цвет фона родительского элемента.
Вывод
Есть много других способов управления цветом фона UIViewController , включая цели или уведомления. Apple разработала UISlider для использования целевого шаблона для передачи данных. Однако, если вы хотите добавить больше функциональности, лучший способ общения от дочернего элемента к его родительскому элементу — создать пользовательский делегат.