UIAlertView与用户提供的上下文和

我已经查看了一些关于如何向UIAlertView提供上下文的想法。 常见的答案是保存在字典或UIAlertView的子类。 我不喜欢在字典中保存上下文的想法,这是数据的错误地方。 UIAlertView的子类化不被Apple支持,所以按照我的标准,这不是一个好的解决scheme。

我提出了一个想法,但我不知道该怎么做。 创build一个作为UIAlertView的委托的上下文对象的实例。 警报视图上下文又有它自己的代表,它是视图控制器。

麻烦是释放记忆。 我将alertView.delegate设置为nil,并调用[self autorelease]以释放-alertView:didDismissWithButtonIndex中的上下文对象。

问题是 :我自己造成什么问题? 我有一个怀疑,我正在设置一个微妙的记忆错误。

这里是仅支持-alertView的简单版本:clickedButtonAtIndex:

使用

- (void)askUserIfTheyWantToSeeRemoteNotification:(NSDictionary *)userInfo { [[[[UIAlertView alloc] initWithTitle:[userInfo valueForKey:@"action"] message:[userInfo valueForKeyPath:@"aps.alert"] delegate:[[WantAlertViewContext alloc] initWithDelegate:self context:userInfo] cancelButtonTitle:@"Dismiss" otherButtonTitles:@"View", nil] autorelease] show]; } - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex withContext:(id)context { if (buttonIndex != alertView.cancelButtonIndex) [self presentViewForRemoteNotification:context]; } 

接口

 @protocol WantAlertViewContextDelegate <NSObject> - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex withContext:(id)context; @end @interface WantAlertViewContext : NSObject <UIAlertViewDelegate> - (id)initWithDelegate:(id<WantAlertViewContextDelegate>)delegate context:(id)context; @property (assign, nonatomic) id<WantAlertViewContextDelegate> delegate; @property (retain, nonatomic) id context; @end 

履行

 @implementation WantAlertViewContext - (id)initWithDelegate:(id<WantAlertViewContextDelegate>)delegate context:(id)context { self = [super init]; if (self) { _delegate = delegate; _context = [context retain]; } return self; } - (void)dealloc { [_context release]; [super dealloc]; } - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { [self.delegate alertView:alertView clickedButtonAtIndex:buttonIndex withContext:self.context]; } - (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex { alertView.delegate = nil; [self autorelease]; } @synthesize delegate = _delegate; @synthesize context = _context; @end 

您可以使用关联对象的概念。 使用函数objc_setAssociatedObject()objc_getAssociatedObject() 。 您可以使用这些属性来实质上添加一个新的属性,在您的情况下,持有一个NSDictionary ,通过一个类别的对象。

这是一个UIAlertView类别的例子。 这些文件应该在没有ARC情况下编译,如果项目使用ARC,则设置-fno-objc-arc标志。

UIAlertView中+ WithContext.h:

 #import <UIKit/UIKit.h> @interface UIAlertView (Context) @property (nonatomic, copy) NSDictionary *userInfo; @end 

UIAlertView中+ WithContext.m:

 #import "UIAlertView+WithContext.h" // This enum is actually declared elseware enum { OBJC_ASSOCIATION_ASSIGN = 0, OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, OBJC_ASSOCIATION_COPY_NONATOMIC = 3, OBJC_ASSOCIATION_RETAIN = 01401, OBJC_ASSOCIATION_COPY = 01403 }; @implementation UIAlertView (Context) static char ContextPrivateKey; -(void)setUserInfo:(NSDictionary *)userInfo{ objc_setAssociatedObject(self, &ContextPrivateKey, userInfo, 3); } -(NSDictionary *)userInfo{ return objc_getAssociatedObject(self, &ContextPrivateKey); } @end 

这个类别很容易使用。

SomeViewController.m:使用ARC或不使用ARC的UIAlertViewDelegate

 -(void)viewDidAppear:(BOOL)animated{ [super viewDidAppear:animated]; UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Title" message:@"Message" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil]; alert.userInfo = [NSDictionary dictionaryWithObject:@"Hello" forKey:@"Greeting"];// autorelease if MRC [alert show]; // release if MRC } -(void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex{ NSLog(@"userInfo:%@",alertView.userInfo); } 

当你按下alertview的OKbutton时,你会看到:

 userInfo:{ Greeting = Hello; } 

几个注意事项:

1)确保关联types匹配属性声明,使事情行为与预期的一样。

2)你可能不应该使用userInfo属性/关联,因为苹果可能决定在将来添加一个userInfo属性到UIAlertView

编辑 为了解决您对[self autorelease];担忧[self autorelease];

从这一行平衡隐式delegate:[[WantAlertViewContext alloc] initWithDelegate:self context:userInfo]保留势在必行: delegate:[[WantAlertViewContext alloc] initWithDelegate:self context:userInfo] 。 你通过调用[self autorelease];达到这个平衡[self autorelease]; 在最后的UIAlertView委托方法中。

当然,这感觉不对。 主要是因为在看这个时候没有办法,一开始看起来不像内存pipe理不当。 但是有一个简单的方法可以避免你正在创build的这个“控制泄漏”的API; 让WantAlertViewContext的实例明确保留自己。 例如:

 -(id)initWithDelegate:(id<WantAlertViewContextDelegate>)delegate context:(id)context{ self = [super init]; if (self) { _delegate = delegate; _context = [context retain]; } return [self retain]; // Explicitly retain self } -(void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex{ alertView.delegate = nil; [self autorelease]; // Or just [self release]; doesn't make much difference at this point } 

现在你的class级有一些内部的和谐。 我说了一些,因为这还不完美。 例如,如果一个实例永远不是alert-view委托,它将永远不会被释放。 这仍然只是一个“半控制”的内存泄漏。

无论如何,现在你的实例化调用看起来更合乎逻辑:

 delegate:[[[WantAlertViewContext alloc] initWithDelegate:self context:userInfo] autorelease]; 

我认为这种特殊的devise模式充满了危险。 如果你最终使用它,密切关注它。

我想出了一个更简单的解决scheme,可能适合某些情况。 因为当委托被调用时,你得到了NSAlertView上下文,我使用对象的实际地址来创build一个标记(NSString *),然后使用它来将自定义值存储在全局或对象特定的NSDictionary中。 这里是一个例子:

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

在代表:

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

呼叫:

 UIAlertView *myAlert = [[UIAlertView alloc] initWithTitle:title_text message:@"" delegate:self cancelButtonTitle:nil otherButtonTitles:button_text ,nil]; CurrentActiveAlerts[[CommandManager GetTag:myAlert]] = CommandToRun; // Querky way to link NSDict to UIAlert, but the best I could think of [myAlert show]; [myAlert release]; 

钥匙最终会看起来像“标签-226811776”。 希望这可以帮助。