如何将变量传递给UIAlertView委托?

24
你如何将一个变量传递给UIAlertView代理?
我有一个变量,我想在警报视图代理中使用。它仅在显示UIAlertViewUIAlertView代理的函数中使用,因此我认为它不应该是控制器的属性。是否有一种方法可以将变量附加到UIAlertView并在代理中检索它?
- (void) someUserCondition:(SOCode *)userCode {
    if ([userCode warrentsConfirmation] > 0) {
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Title" message:@"Are you sure?" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"OK",nil];        
        [alert setAlertViewStyle:UIAlertViewStyleDefault];  
        //TODO somehow store the code variable on the alert view
        [alert show];
    }
}

- (void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex   {
    NSString *title = [alertView buttonTitleAtIndex:buttonIndex];
    if ([title isEqualToString:@"OK"]){
       SOCode *userCode = //TODO somehow get the code from the alert view
       [self continueWithCode:code];
    }                                 
}

2
可能是重复的问题:如何将userInfo添加到UIAlertView? - jscs
6个回答

26

在接口之前的 .h 文件中:

extern const char MyConstantKey;
@interface ViewController...

在 .m 文件中导入:

import <objc/runtime.h>

在 .m 文件实现之前

const char MyConstantKey;

在.m实现文件中

-(void)viewDidAppear:(BOOL)animated{ //or wherever

    NSString *aString = @"This is a string";

    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Testing" message:@"test is test" delegate:self cancelButtonTitle:@"Okay" otherButtonTitles:nil];

    [alert show];

    [alert release];

    objc_setAssociatedObject(alert, &MyConstantKey, aString, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

 }

在 .m 文件中的 alertview 回调函数

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

     NSString *associatedString = objc_getAssociatedObject(alertView, &MyConstantKey);

     NSLog(@"associated string: %@", associatedString);

}

为什么我们需要在 .h 文件中声明 'extern const char MyConstantKey',而在 .m 文件中声明 const char MyConstantKey? - Srinivasan N
使用此解决方案时,请注意以下问题:https://dev59.com/_3zaa4cB1Zd3GeqPLhzg - ben-efiz
我得到了“Undefined symbols for architecture x86_64: _MyConstantKey”的错误提示: - kemdo

14

使用关联对象 Associated Objects。在这里有更详细的描述:Your New Friends: Obj-C Associated Objects

设置对象时使用:

objc_setAssociatedObject(alert, &key, userCode, OBJC_ASSOCIATION_RETAIN);

然后将它取回:

SOCode *userCode = objc_getAssociatedObject(alertView, &key);

你还需要添加 static char key;,以便它在两个方法的范围内。

更新

我已经将这个方法封装成了UIAlertView类别。你可以使用Cocoapods来引入:

pod 'HCViews/UIAlertViewHCContext', '~> 1.2'

源代码在此处获取:https://github.com/hypercrypt/HCViews/blob/master/Categories/UIAlertView%2BHCContext.h


7
很多文章都在讲解相关对象的概念(这很好!),但有时候你只想看代码。下面是一个简单干净的分类,你可以将其放在一个单独的文件中,或者放在你现有的.m文件界面上方。(你甚至可以用NSObject替换UIAlertView,有效地为任何对象添加context属性):
#import <objc/runtime.h>

@interface UIAlertView (Private)
@property (nonatomic, strong) id context;
@end

@implementation UIAlertView (Private)
@dynamic context;
-(void)setContext:(id)context {
    objc_setAssociatedObject(self, @selector(context), context, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(id)context {
    return objc_getAssociatedObject(self, @selector(context));
}
@end

然后,您将能够执行以下操作之一:
NSObject *myObject = [NSObject new];

UIAlertView *alertView = ...
alertView.context = myObject;

重要提示:dealloc中不要忘记将上下文设置为nil!!


嗨,你说的“在dealloc中不要忘记将上下文设置为nil”是什么意思? - bobsacameno

3

UIAlertViewUIView的子类,它具有可以设置为整数的tag属性。不幸的是,如果您需要其他内容来标识/传递信息给代理,则需要在代理本身上设置一些属性(或设置具有标记索引的数组)。Advaith的方法可能有效,但从技术上讲,这不受Apple支持。

    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Title" message:@"Are you sure?" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"OK",nil];        
    [alert setAlertViewStyle:UIAlertViewStyleDefault];  
    alert.tag = SOMEINTEGER;
    [alert show];

1
这对于快速解决问题而言相当好,但是如果:1.你不需要传递一个整数而是一个字符串;2.如果你有另一个警报视图具有不同的操作,并且你想根据其标签编写其操作,该怎么办? - arniotaki

1

我怀疑最直接的方法是在警告视图的委托类中设置一个属性。 警告视图没有任何提供“用户信息”的功能,并且不支持子类化,这消除了我能想到的唯一的快捷方式。


1
它确实支持子类化。 - Jonathan Grynspan
8
UIAlertView类旨在按原样使用,不支持子类化。 - Jeffery Thomas
@评论员们:他并没有建议子类化UIAlertView,而是在委托类中添加一个属性(例如,使用AlertView的ViewController)。在我看来,这是一个有效的选择。 - avf

0

子类化UIAlertView,添加一个名为userInfo的属性,类型由您选择。在创建Subclassed UIAlertView实例时设置用户信息值,并从委托方法中检索它。(在那里,您将获得持有userInfo的子类化实例)


5
不应该对UIAlertView进行子类化。 - hypercrypt
@hypercrypt:我想我知道为什么你说UIAlertView不应该被子类化,但你能分享一下你的原因吗?(下面有一条评论解释了这个问题) - Mattia
@hypercrypt 为什么你说我们不应该子类化UIAlertView?我尝试了一个例子,效果很棒啊! - Advaith
1
正如Jeffery Thomas在下面发布的那样,UIAlertView类参考:UIAlertView类旨在按原样使用,不支持子类化。该类的视图层次结构是私有的,不得修改。 - hypercrypt
除了我上面的评论之外,虽然它可能在iOS 5上运行,但在iOS 6、7或8上可能不会。由于苹果已明确告诉您不要子类化UIAlertView,因此他们保留将来更改它的权利,例如将其转换为类簇。如果他们这样做,那么您的代码肯定会出现问题。 - hypercrypt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接