开发者

How to add userInfo to a UIAlertView?

I would like to know how to add a userInfo object, or any NSDictionary, to a UIAlertView?

Than开发者_如何学Ck you.


You could try subclassing UIAlertView to add the field, or store a reference in your delegate class instead. But the most general way to attach any object to any other object is to use objc_setAssociatedObject.

To do so, you have to #import <objc/runtime.h>, and you need an arbitrary void * that is used as a key (the usual trick is to declare a static char fooKey; in your .m file and use its address). Then you can attach the object like this:

objc_setAssociatedObject(alertView, &fooKey, myDictionary, OBJC_ASSOCIATION_RETAIN);

In this case, myDictionary will be retained for the life of the alertView and will be released when the alertView is deallocated.

To retrieve your associated object later, use the logically named objc_getAssociatedObject.

NSDictionary *myDictionary = objc_getAssociatedObject(alertView, &fooKey);

It returns nil if there was no association set. To break the association, just use objc_setAssociatedObject to associate a new value for the same object and key; nil can be used to break the association without associating a new object.

Other values for the type of association besides OBJC_ASSOCIATION_RETAIN are listed here.


I wrote a (well-tested) category on NSObject that gives every object the capability to easily store data.

Just put the code in a header and implementation file and import it in any of your projects. Or put it in a static library. Mac OS X 10.6+ and iOS (version?) only.

#import <Foundation/Foundation.h>
#import <objc/runtime.h>

@interface NSObject (CCFoundation)

- (id)associativeObjectForKey: (NSString *)key;
- (void)setAssociativeObject: (id)object forKey: (NSString *)key;

@end

#pragma mark -

@implementation NSObject (CCFoundation)

static char associativeObjectsKey;

- (id)associativeObjectForKey: (NSString *)key {
    NSMutableDictionary *dict = objc_getAssociatedObject(self, &associativeObjectsKey);
    return [dict objectForKey: key];
}

- (void)setAssociativeObject: (id)object forKey: (NSString *)key {
    NSMutableDictionary *dict = objc_getAssociatedObject(self, &associativeObjectsKey);
    if (!dict) {
        dict = [[NSMutableDictionary alloc] init];
        objc_setAssociatedObject(self, &associativeObjectsKey, dict, OBJC_ASSOCIATION_RETAIN);
    } [dict setObject: object forKey: key];
}

@end

Simply put, every object becomes an easy-to-use dictionary (thanks to NSMutableDictionary) as soon as you need one. The dictionary is released when the object is and the dictionary's objects are released when the dictionary is released. It's amazing how Apple made this simple.

Warning 1: The code above is ARC enabled. It's well-tested and is used in several shipped products. I didn't see yet any memory leaks or performance issues.

Warning 2: Rename the methods as you wish, but if you choose to keep the name, make sure you add a prefix. This is a category on a root object, people. Some class somewhere is using this method name and you don't want to interfere! My static library which I include in every project uses the method names associativeCCObjectForKey: and setAssociativeCCObject:forKey:.

I hope this helps anybody wanting to have a simple userInfo-like feature on every object. You're welcome! :-)


If you are on > iOS 4.0 (for blocks) and you only want one or two buttons, you could use this category I made:

https://github.com/rsaunders100/UIAlertView-Blocks

It bypasses the need to add user info since you put your click handeling function straight into the alert. e.g.

 #import UIAlertView+Blocks.h

 ...

 ...

 NSString* myUserInfo = @"example";

 [UIAlertView displayAlertWithTitle:@"Example Alert View With Blocks"
                            message:nil
                    leftButtonTitle:@"Ok"
                  leftButtonAction:^{
                                      NSLog(@"%@", myUserInfo);
                                    } 
                  rightButtonTitle:nil
                 rightButtonAction:nil];


It works for me if i give it a literal c string such as "key" instead of creating a static char

Instead, taking into account what Anomie says, you could instead do this:

objc_setAssociatedObject ( alert , (const void*)0x314 , notification , OBJC_ASSOCIATION_RETAIN ) ;

This works for anything which allows you to use arbitrary void* (observation, this function, etc) and requires no extra static variable tricks. Also, (const void*)0x314 is ALWAYS 0x314, no matter what the compiler does.

Also, Anomie, you just saved me a LOT of work in an app I'm working on right now. Thanks!


I've come up with a simpler solution that may fit in some circumstances. Because you get the NSAlertView context when the delegate gets called, I use the actual address of the object to make a tag (NSString*) which I then use to store custom values in a global or object specific NSDictionary. Here is an example:

+(NSString*)GetTag:(id)ObjectIn
{
    return [NSString stringWithFormat:@"Tag-%i",(int)ObjectIn];
}

In the Delegate:

-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
    NSString* MyID = [CommandManager GetTag:alertView];
    [CurrentActiveAlerts removeObjectForKey:MyID];
}

Calling:

    UIAlertView *myAlert = [[UIAlertView alloc] initWithTitle:title_text
                                                          message:@""
                                                     delegate:self
                                            cancelButtonTitle:nil
                                        otherButtonTitles:button_text ,nil];

    CurrentActiveAlerts[[CommandManager GetTag:myAlert]] = CommandToRun;  
    [myAlert show];
    [myAlert release];

The keys will end up looking like "Tag-226811776". Hope this helps.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜