Существуют ситуации, в которых вам необходимо отображать более одного AlertView или ActionSheet и, более того, обрабатывать нажатие кнопки. При этом мы наблюдаем следующее - код вызова данных элементов отделен от кода обработки.
В таком случае логично определить для каждого вызываемого объекта идентификатор (свойство tag) и направлять ответ пользователя на обработку тому или иному методу. В результате мы получим нечто вроде этого:
#pragma mark - Calling Alerts
- (IBAction)btn_callAlertOne:(id)sender {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"First Alert" message:@"Alert message" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:@"Boom",nil];
alert.tag = 1;
[alert show];
}
- (IBAction)btn_callAlertTwo:(id)sender {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Second Alert" message:@"Alert message" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:@"Boom",nil];
alert.tag = 2;
[alert show];
}
- (IBAction)btn_callAlertThree:(id)sender {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Third Alert" message:@"Alert message" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:@"Boom",nil];
alert.tag = 3;
[alert show];
}
- (IBAction)btn_callAlertFour:(id)sender {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Fourth Alert" message:@"Alert message" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:@"Boom",nil];
alert.tag = 4;
[alert show];
}
#pragma mark - UIAlertView Delegate
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
switch (alertView.tag) {
case 1:
[self alertView_firstAlertClickedButtonAtIndex:buttonIndex];
break;
case 2:
[self alertView_secondAlertClickedButtonAtIndex:buttonIndex];
break;
case 3:
[self alertView_thirdAlertClickedButtonAtIndex:buttonIndex];
break;
case 4:
[self alertView_fourthAlertClickedButtonAtIndex:buttonIndex];
break;
}
}
- (void)alertView_firstAlertClickedButtonAtIndex:(NSInteger)buttonIndex {
switch (buttonIndex) {
case 0:
break;
case 1:
break;
}
}
- (void)alertView_secondAlertClickedButtonAtIndex:(NSInteger)buttonIndex {
switch (buttonIndex) {
case 0:
break;
case 1:
break;
}
}
- (void)alertView_thirdAlertClickedButtonAtIndex:(NSInteger)buttonIndex {
switch (buttonIndex) {
case 0:
break;
case 1:
break;
}
}
- (void)alertView_fourthAlertClickedButtonAtIndex:(NSInteger)buttonIndex {
switch (buttonIndex) {
case 0:
break;
case 1:
break;
}
}
Даже с отсутствующими алгоритмами обработки нажатий данный код выглядит массивно. Для каждого сообщения (alert или actionsheet) определяется метод вызова и метод обработки, плюс общий метод сортировки.
Упростить данную структуру можно, если описать обработку нажатий при создании сигнала. Для этого необходимо ассоциировать блок обработки с сигналом. Сделать это можно с помощью функции objc_setAssociatedObject, доступной в runtime.
Взглянем на описание функции:
/**
* Sets an associated value for a given object using a given key and association policy.
*
* @param object The source object for the association.
* @param key The key for the association.
* @param value The value to associate with the key key for object. Pass nil to clear an existing association.
* @param policy The policy for the association. For possible values, see “Associative Object Behaviors.”
*
* @see objc_setAssociatedObject
* @see objc_removeAssociatedObjects
*/
OBJC_EXPORT void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy);
Воспользуемся ассоциированным объектом. Назначим блок обработки в качестве значения (value). Импортируем заголовок runtime и добавим ключ.
// Импорт
#import
// Определим ключ
static void *ALMyAlertViewKey = "ALMyAlertViewKey";
- (IBAction)btn_callAlertOne:(id)sender {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"First Alert" message:@"Alert message" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:@"Boom",nil];
objc_setAssociatedObject(alert, ALMyAlertViewKey, ^(NSInteger buttonIndex){
switch (buttonIndex) {
case 0:
break;
case 1:
break;
}
}, OBJC_ASSOCIATION_COPY);
[alert show];
}
- (IBAction)btn_callAlertTwo:(id)sender {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Second Alert" message:@"Alert message" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:@"Boom",nil];
objc_setAssociatedObject(alert, ALMyAlertViewKey, ^(NSInteger buttonIndex){
switch (buttonIndex) {
case 0:
break;
case 1:
break;
}
}, OBJC_ASSOCIATION_COPY);
[alert show];
}
- (IBAction)btn_callAlertThree:(id)sender {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Third Alert" message:@"Alert message" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:@"Boom",nil];
objc_setAssociatedObject(alert, ALMyAlertViewKey, ^(NSInteger buttonIndex){
switch (buttonIndex) {
case 0:
break;
case 1:
break;
}
}, OBJC_ASSOCIATION_COPY);
[alert show];
}
- (IBAction)btn_callAlertFour:(id)sender {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Fourth Alert" message:@"Alert message" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:@"Boom",nil];
objc_setAssociatedObject(alert, ALMyAlertViewKey, ^(NSInteger buttonIndex){
switch (buttonIndex) {
case 0:
break;
case 1:
break;
}
}, OBJC_ASSOCIATION_COPY);
[alert show];
}
#pragma mark - UIAlertView Delegate
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
void (^associatedBlock)(NSInteger) = objc_getAssociatedObject(alertView, ALMyAlertViewKey);
associatedBlock(buttonIndex);
}
Девять методов сократились до пяти. Теперь код создания сигнального окна и обработки результата находятся в одном месте.
Главный обработчик -alertView:clickedButtonAtIndex: теперь содержит две строки: первая получает ассоциированный объект (value), а именно наш блок, а вторая передает индекс нажатой кнопки данному блоку.
Для ActionSheet методы выглядят следующим образом:
// Импорт
#import
// Определим ключ
static void *ALMyActionSheetKey = "ALMyActionSheetKey";
- (IBAction)btn_callActivitySheetOne:(id)sender {
NSString *actionSheetTitle = @"1st Action Sheet title";
NSString *destructiveButtonTitle = @"Red button";
NSString *cancelTitle = @"Cancel";
UIActionSheet *actionSheet = [[UIActionSheet alloc]
initWithTitle:actionSheetTitle
delegate:self
cancelButtonTitle:cancelTitle
destructiveButtonTitle:destructiveButtonTitle
otherButtonTitles:nil];
objc_setAssociatedObject(actionSheet, ALMyActionSheetKey, ^(NSInteger buttonIndex){
switch (buttonIndex) {
case 0:
break;
case 1:
break;
}
}, OBJC_ASSOCIATION_COPY);
[actionSheet showInView:self.view];
}
- (IBAction)btn_callActivitySheetTwo:(id)sender {
NSString *actionSheetTitle = @"2nd Action Sheet title";
NSString *destructiveButtonTitle = @"Red button";
NSString *cancelTitle = @"Cancel";
UIActionSheet *actionSheet = [[UIActionSheet alloc]
initWithTitle:actionSheetTitle
delegate:self
cancelButtonTitle:cancelTitle
destructiveButtonTitle:destructiveButtonTitle
otherButtonTitles:nil];
objc_setAssociatedObject(actionSheet, ALMyActionSheetKey, ^(NSInteger buttonIndex){
switch (buttonIndex) {
case 0:
break;
case 1:
break;
}
}, OBJC_ASSOCIATION_COPY);
[actionSheet showInView:self.view];
}
- (IBAction)btn_callActivitySheetThree:(id)sender {
NSString *actionSheetTitle = @"3rd Action Sheet title";
NSString *destructiveButtonTitle = @"Red button";
NSString *cancelTitle = @"Cancel";
UIActionSheet *actionSheet = [[UIActionSheet alloc]
initWithTitle:actionSheetTitle
delegate:self
cancelButtonTitle:cancelTitle
destructiveButtonTitle:destructiveButtonTitle
otherButtonTitles:nil];
objc_setAssociatedObject(actionSheet, ALMyActionSheetKey, ^(NSInteger buttonIndex){
switch (buttonIndex) {
case 0:
break;
case 1:
break;
}
}, OBJC_ASSOCIATION_COPY);
[actionSheet showInView:self.view];
}
- (IBAction)btn_callActivitySheetFour:(id)sender {
NSString *actionSheetTitle = @"4th Action Sheet title";
NSString *destructiveButtonTitle = @"Red button";
NSString *cancelTitle = @"Cancel";
UIActionSheet *actionSheet = [[UIActionSheet alloc]
initWithTitle:actionSheetTitle
delegate:self
cancelButtonTitle:cancelTitle
destructiveButtonTitle:destructiveButtonTitle
otherButtonTitles:nil];
objc_setAssociatedObject(actionSheet, ALMyActionSheetKey, ^(NSInteger buttonIndex){
switch (buttonIndex) {
case 0:
break;
case 1:
break;
}
}, OBJC_ASSOCIATION_COPY);
[actionSheet showInView:self.view];
}
#pragma mark - UIActionSheet Delegate
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
void (^associatedBlock)(NSInteger) = objc_getAssociatedObject(actionSheet, ALMyActionSheetKey);
associatedBlock(buttonIndex);
}