Блок для UIAlertViewDelegate
Я новичок в объекте C, и я просто пытаюсь выяснить, могу ли я использовать блок или селектор в качестве аргумента UIAlertViewDelegate для UIAlertView - и что более уместно?
Я пробовал следующее, но он просто не работает, поэтому я не уверен, что я на правильном пути или нет?
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Checked In"
message:responseString
delegate:^(UIAlertView * alertView, NSInteger buttonIndex)
{
NSLog(@"Done!");
}
cancelButtonTitle:@"OK"
otherButtonTitles: nil];
Спасибо!
Ответы
Ответ 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];
Ответ 7
Вот моя реализация, похоже, похоже на большинство ответов здесь:
http://stavash.wordpress.com/2013/01/31/quick-tip-uialertview-with-a-block-callback/
Ответ 8
Просто используйте REKit. Он похож на BlocksKit, но он более мощный.
Ответ 9
Отметьте категорию UIAlertView-Blocks в Github.
Я написал это и очень прост в использовании и хорошо работает.
Удачи.
Ответ 10
Вот еще одна полезная библиотека, чтобы сделать то же самое. http://bit.ly/ichalrtvw
Код здесь: http://bit.ly/ichalertview
Ответ 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];