Подтвердить что ты не робот

Блок для UIAlertViewDelegate

Я новичок в объекте C, и я просто пытаюсь выяснить, могу ли я использовать блок или селектор в качестве аргумента UIAlertViewDelegate для UIAlertView - и что более уместно?

Я пробовал следующее, но он просто не работает, поэтому я не уверен, что я на правильном пути или нет?

    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Checked In" 
    message:responseString
    delegate:^(UIAlertView * alertView, NSInteger buttonIndex)
                                                    {
                                                       NSLog(@"Done!");
                                                   } 
    cancelButtonTitle:@"OK" 
    otherButtonTitles: nil];

Спасибо!

4b9b3361

Ответ 1

Отличная идея. Вот. Точно так же, как вид предупреждения, кроме добавления свойства блока, которое вызывается, когда предупреждение отклоняется. (Edit - я упростил этот код с момента первоначального ответа. Вот что я сейчас использую в проектах)

//  AlertView.h
//

#import <UIKit/UIKit.h>

@interface AlertView : UIAlertView

@property (copy, nonatomic) void (^completion)(BOOL, NSInteger);

- (id)initWithTitle:(NSString *)title message:(NSString *)message cancelButtonTitle:(NSString *)cancelButtonTitle otherButtonTitles:(NSArray *)otherButtonTitles;

@end

//
//  AlertView.m

#import "AlertView.h"

@interface AlertView () <UIAlertViewDelegate>

@end

@implementation AlertView

- (id)initWithTitle:(NSString *)title message:(NSString *)message cancelButtonTitle:(NSString *)cancelButtonTitle otherButtonTitles:(NSArray *)otherButtonTitles {

    self = [self initWithTitle:title message:message delegate:self cancelButtonTitle:cancelButtonTitle otherButtonTitles:nil];

    if (self) {
        for (NSString *buttonTitle in otherButtonTitles) {
            [self addButtonWithTitle:buttonTitle];
        }
    }
    return self;
}

- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {

    if (self.completion) {
        self.completion(buttonIndex==self.cancelButtonIndex, buttonIndex);
        self.completion = nil;
    }
}

@end

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

Назовите его следующим образом:

AlertView *alert = [[AlertView alloc] initWithTitle:@"Really Delete" message:@"Do you really want to delete everything?" cancelButtonTitle:@"Nevermind" otherButtonTitles:@[@"Yes"]];

alert.completion = ^(BOOL cancelled, NSInteger buttonIndex) {
    if (!cancelled) {
        [self deleteEverything];
    }
};
[alert show];

Ответ 2

Посмотрите эту категорию UIAlertView-Blocks на github. Я использую это, и он работает хорошо.

Ответ 3

Это обновление для реализации danh, которое является неполным, потому что невозможно добавить несколько кнопок. Передача va_list в функцию немного сложна: -)

Итак, вы можете сделать это, чтобы иметь возможность добавлять несколько кнопок в UIAlertView:

- (id)initWithTitle:(NSString *)title message:(NSString *)message completion:(void (^)(NSInteger buttonIndex))completion cancelButtonTitle:(NSString *)cancelButtonTitle otherButtonTitles:(NSString *)otherButtonTitles, ... {

    self = [super initWithTitle:title message:message delegate:self cancelButtonTitle:cancelButtonTitle otherButtonTitles:nil ];


    if(self){
        _completion = completion;

        va_list _arguments;
        va_start(_arguments, otherButtonTitles);

        for (NSString *key = otherButtonTitles; key != nil; key = (__bridge NSString *)va_arg(_arguments, void *)) {
                [self addButtonWithTitle:key];
        }
        va_end(_arguments);

    }

    return self;
}

Обновить. Возможно, лучший способ передачи va_list в super. Я хотел бы упомянуть, что для меня va_list есть что-то мистическое: -)

Ответ 4

Удивительная идея. Я только что закончил именно вашу идею с использованием шаблона категории, без подкласса, напрямую вызываю UIAlertView. Выполните следующие действия:

  • Категория UIAlertView в .h файле

    @interface UIAlertView (AlertWithBlock)
    
       - (void (^)(UIAlertView *alertView, NSInteger buttonIndex))delegateBlock;
       - (void)setDelegateBlock:(void (^)(UIAlertView *alertView, NSInteger buttonIndex))delegateBlock;
    
       + (id)alertWithTitle:(NSString *)title message:(NSString *)message cancelButtonTitle:(NSString   *)cancelButtonTitle otherButtonTitles:(NSArray *)otherButtonTitles delegate:(void (^)(UIAlertView *alertView, NSInteger buttonIndex))delegate;
    
    @end
    
  • В .m файле

    @implementation UIAlertView(AlertWithBlock)
    
    static char const *delegateBlockTagKey = "delegateBlockTagKey";
    
    - (void (^)(UIAlertView *alertView, NSInteger buttonIndex))delegateBlock
    {
        return objc_getAssociatedObject(self, delegateBlockTagKey);
    }
    
    - (void)setDelegateBlock:(void (^)(UIAlertView *alertView, NSInteger buttonIndex))delegateBlock
    {
        objc_setAssociatedObject(self, delegateBlockTagKey, delegateBlock, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    
    + (id)alertWithTitle:(NSString *)title message:(NSString *)message cancelButtonTitle:(NSString *)cancelButtonTitle otherButtonTitles:(NSArray *)otherButtonTitles delegate:(void (^)(UIAlertView *alertView, NSInteger buttonIndex))delegate
    {
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title message:message delegate:nil cancelButtonTitle:cancelButtonTitle otherButtonTitles:nil];
        alert.delegate = alert;
        alert.delegateBlock = [delegate copy];
    
        for (NSString *buttonTitle in otherButtonTitles)
        {
            [alert addButtonWithTitle:buttonTitle];
        }
    
        [alert show];
    
        return alert;
    }
    
    #pragma mark - Delegate
    -(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
    {
        if (alertView.delegateBlock)
        {
            alertView.delegateBlock(alertView, buttonIndex);
        }
    }
    
    @end
    
  • Назовите это

    [UIAlertView alertWithTitle:@"Title" message:@"This is a message" cancelButtonTitle:@"Cancel" otherButtonTitles:@[@"Yes",@"No"] delegate:^(UIAlertView *alertView, NSInteger buttonIndex) {
    NSLog(@"Click at button index %ld", buttonIndex);
    }];
    

Надеюсь, что это поможет.

Ответ 5

Я написал простое расширение в Swift, надеюсь, что это полезно

import UIKit

extension UIAlertView {

    func show(completion: (alertView: UIAlertView, buttonIndex: Int) -> Void){
        self.delegate = AlertViewDelegate(completion: completion)
        self.show()
    }

    class func showInput(title: String?, message: String?, cancellable: Bool, completion: (text: String?) -> Void){

        var strOK = NSLocalizedString("OK",comment: "OK")
        var strCancel = NSLocalizedString("Cancel",comment: "Cancel")
        var alert = UIAlertView(title: title, message: message, delegate: nil, cancelButtonTitle: cancellable ? strCancel : strOK)
        alert.alertViewStyle = UIAlertViewStyle.PlainTextInput
        if(cancellable) {
            alert.addButtonWithTitle(strOK)
        }
        alert.show { (alertView, buttonIndex) -> Void in
            if(cancellable && alertView.cancelButtonIndex == buttonIndex) {
                completion(text: nil)
                return
            }
            completion(text: alertView.textFieldAtIndex(0)?.text)
        }
    }

    private class AlertViewDelegate : NSObject, UIAlertViewDelegate {
        var completion :  (alertView: UIAlertView, buttonIndex: Int) -> Void
        var retainedSelf : NSObject?
        init(completion: (UIAlertView, Int) -> Void ) {
            self.completion = completion
            super.init()

            self.retainedSelf = self
        }

        func alertView(alertView: UIAlertView, didDismissWithButtonIndex buttonIndex: Int) {
            var retain = self
            retain.retainedSelf = nil
            retain.completion(alertView: alertView, buttonIndex: buttonIndex)
        }
    }
}

Ответ 6

Для этого подхода следует использовать UIAlertController, поскольку документ Apple говорит

Объект UIAlertController отображает пользователю предупреждение. Эта класс заменяет классы UIActionSheet и UIAlertView для отображение предупреждений. После настройки контроллера предупреждения с помощью действий и стиля, которые вы хотите, представить его с помощью presentViewController: анимированный: завершение: метод.

Помимо отображения сообщения пользователю, вы можете связать действия с вашим контроллером предупреждений, чтобы дать пользователю возможность ответить. Для каждого действия, которое вы добавляете с помощью метода addAction:, предупреждение контроллер настраивает кнопку с деталями действия. Когда пользователь отбирает это действие, контроллер предупреждения выполняет блок, который вы предоставили при создании объекта действия. Apple Docs.

UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"My Alert"


       message:@"This is an alert."
                                   preferredStyle:UIAlertControllerStyleAlert];

    UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault
       handler:^(UIAlertAction * action) {}];

    [alert addAction:defaultAction];
    [self presentViewController:alert animated:YES completion:nil];

Ответ 8

Просто используйте REKit. Он похож на BlocksKit, но он более мощный.

Ответ 11

Мне пришлось немного изменить вызывающий пример, чтобы остановить ошибку complier. Просто небольшая настройка и xcode были счастливы.

UIAlertViewBlock *alert = [[UIAlertViewBlock alloc] initWithTitle:@"hi"
                                                          message:@"hi there"
                                                       completion:^(BOOL canceled,NSInteger buttonIndex) {
                                                           NSLog(@"canceled=%d", canceled);
                                                           NSLog(@"pressed=%d", buttonIndex);
                                                       }
                                               cancelButtonTitle:@"cancel"
                                                otherButtonTitles:@"ok", nil];
[alert show];