Как я могу выполнить обработчик UIAlertAction?

Я пытаюсь написать вспомогательный класс, чтобы наше приложение могло поддерживать как UIAlertAction, так и UIAlertView. Однако при написании метода alertView:clickedButtonAtIndex: для UIAlertViewDelegate я столкнулся с проблемой: я не вижу возможности выполнить код в блоке обработчика UIAlertAction.

Я пытаюсь сделать это, сохраняя массив UIAlertAction в свойстве с именем handlers.

@property (nonatomic, strong) NSArray *handlers;

а затем реализовать такой делегат:

- (void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
    UIAlertAction *action = self.handlers[buttonIndex];
    if (action.enabled)
        action.handler(action);
}

Тем не менее, нет свойства action.handler или какого-либо другого способа, которым я могу его получить, поскольку заголовок UIAlertAction просто имеет:

NS_CLASS_AVAILABLE_IOS(8_0) @interface UIAlertAction : NSObject <NSCopying>

+ (instancetype)actionWithTitle:(NSString *)title style:(UIAlertActionStyle)style handler:(void (^)(UIAlertAction *action))handler;

@property (nonatomic, readonly) NSString *title;
@property (nonatomic, readonly) UIAlertActionStyle style;
@property (nonatomic, getter=isEnabled) BOOL enabled;

@end

Есть ли другой способ выполнить код в блоке handler блока UIAlertAction?


person Ky Leggiero    schedule 21.04.2015    source источник
comment
Возможно, это не тот ответ, который вы ищете (что я в любом случае не уверен), но пробовали ли вы передавать некоторые блоки для своих действий, а не использовать обработчики? Поэтому сохраните другой источник данных для действий, которые вы хотите запустить, на основе выбранного индекса.   -  person timgcarlson    schedule 21.04.2015
comment
@timgcarlson мне также нужно будет указать способ передачи текста, стиля и возможности действий?   -  person Ky Leggiero    schedule 21.04.2015


Ответы (2)


После некоторых экспериментов я только что понял это. Оказывается, блок-обработчик можно привести к указателю на функцию, а указатель на функцию можно выполнить.

Вот так

//Get the UIAlertAction
UIAlertAction *action = self.handlers[buttonIndex];

//Cast the handler block into a form that we can execute
void (^someBlock)(id obj) = [action valueForKey:@"handler"];

//Execute the block
someBlock(action);
person Drew H    schedule 28.04.2016
comment
Используются ли непубличные API? Apple не допустит приложение в Магазин, если оно есть. - person Ky Leggiero; 29.04.2016
comment
Я не знаю, будет ли Apple звонить в приложение для этого. Я использую его для модульных тестов (которые не создаются как часть двоичного файла приложения). - person Drew H; 29.04.2016
comment
Если вы пытаетесь выполнить один и тот же блок кода как снаружи, так и внутри дескриптора, я бы реорганизовал код в отдельный метод или переместил код в блок и выполнил блок в обработчике. Помимо модульного тестирования, я не могу придумать причину, по которой нужно было бы выполнять обработчик UIAlertAction. - person Drew H; 29.04.2016
comment
Я пытаюсь создать класс-оболочку, чтобы сохранить совместимость с iOS 7, используя как UIAlertController, так и UIAlertView. - person Ky Leggiero; 02.05.2016

Классы-обертки великолепны, не так ли?

В .h:

@interface UIAlertActionWrapper : NSObject

@property (nonatomic, strong) void (^handler)(UIAlertAction *);
@property (nonatomic, strong) NSString *title;
@property (nonatomic, assign) UIAlertActionStyle style;
@property (nonatomic, assign) BOOL enabled;

- (id) initWithTitle: (NSString *)title style: (UIAlertActionStyle)style handler: (void (^)(UIAlertAction *))handler;

- (UIAlertAction *) toAlertAction;

@end

и в .m:

- (UIAlertAction *) toAlertAction
{
    UIAlertAction *action = [UIAlertAction actionWithTitle:self.title style:self.style handler:self.handler];
    action.enabled = self.enabled;
    return action;
}

...

- (void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
    UIAlertActionWrapper *action = self.helpers[buttonIndex];
    if (action.enabled)
        action.handler(action.toAlertAction);
}

Все, что вам нужно сделать, это убедиться, что UIAlertActionWrapper вставлены в helpers вместо UIAlertAction.

Таким образом, вы можете сделать все свойства доступными и устанавливаемыми по своему усмотрению и при этом сохранить функциональность, предоставляемую исходным классом.

person Ky Leggiero    schedule 21.04.2015
comment
Пожалуйста, объясните любые отрицательные голоса сопровождающим комментарием, чтобы я знал, как лучше ответить в будущем :) - person Ky Leggiero; 02.05.2016