Вопрос по iphone, objective-c – Блок для UIAlertViewDelegate

25

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

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

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

Спасибо!

Apple не предлагает, но это хорошая идея. Способ сделать это - подкласс. Я сделаю один очень быстро и отправлю это. danh
твет @ danh работает, но он не поддерживает несколько кнопок. Смотрите мой ответ ниже. Besi

Ваш Ответ

11   ответов
-2

чтобы остановить ошибку компилятора. Просто небольшой твик и 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];
2

как говорится в документе Apple

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

Помимо отображения сообщения пользователю, вы можете связать действия с вашим контроллером оповещений, чтобы дать пользователю возможность ответить. Для каждого действия, добавляемого с помощью метода 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];
28

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

//  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];
Вы пытались добавить несколько кнопок?:-) см. мой ответ ниже. Besi
Может быть, я упускаю ваш первый пункт, но cancelButtonTitle передается нативному init. Что касается параметра self для блока, я думаю, что он лучше подходит для шаблона делегата, чем для блока. Это должна быть слабая копия, чтобы избежать цикла сохранения. Но cancelButtonIndex в качестве параметра может быть хорошим дополнением. danh
Вот (более полная) реализация идеи Данха: Blog.mugunthkumar.com / кодирования / ... thelaws
Если я что-то не замечаю, вы не используетеcancelButtonTitle параметр. Также было бы полезно иметь само оповещение в качестве аргумента блока (как в методе делегата), чтобы индекс кнопки можно было сравнить сalert.cancelButtonIndex. omz
Спасибо @Besi. Обновлен ответ, чтобы ваш код правильно обрабатывал var args. danh
1

UIAlertView-блоки Категория на GitHub. Я использую это, и это работает хорошо.

1

используя шаблон категории, без подкласса, вызовите непосредственно 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);
}];

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

Ницца! Не забывайте #import <objc / runtime.h> Fracdroid
0
1

которое является неполным, поскольку невозможно добавить несколько кнопок. Передача 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 @ есть что-то мистическое для них: -)

Это хороший улов. Спасибо за подсказки. Я отредактирую свой ответ на случай, если он пропущен. danh
0

REKit. Он похож на BlocksKit, но он более мощный.

1

надеюсь, оно будет полезным

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)
        }
    }
}
0

Категория UIAlertView-Blocks на Github. Я написал это и очень прост в использовании и хорошо работает.

Удачи

Похожие вопросы