Делегаты являются полезным инструментом в общении между объектами. В этом уроке мы создадим и реализуем пользовательский делегат, который позволит трем 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
для использования целевого шаблона для передачи данных. Однако, если вы хотите добавить больше функциональности, лучший способ общения от дочернего элемента к его родительскому элементу — создать пользовательский делегат.