使用用户提供的上下文和[self autorelease]的UIAlertView [英] UIAlertView with a user supplied context and [self autorelease]

查看:83
本文介绍了使用用户提供的上下文和[self autorelease]的UIAlertView的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经了解了如何为UIAlertView提供上下文的一些想法。常见的答案是将它保存在字典或子类UIAlertView中。我不喜欢在字典中保存上下文的想法,这是数据的错误位置。 Apple不支持对UIAlertView进行子类化,因此根据我的标准,这不是一个好的解决方案。

I have looked over some ideas for how to supply a context to a UIAlertView. The common answers are save it in a dictionary or subclass UIAlertView. I don't like the idea of saving the context in a dictionary, it's the wrong place for the data. Subclassing UIAlertView is not supported by Apple, so by my standard, is not a good solution.

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

I came up with an idea, but I'm not sure what to make of it. Create an instance of a context object that is the delegate of UIAlertView. The alert view context, in turn, has it's own delegate which is the view controller.

麻烦在于释放内存。我将alertView.delegate设置为nil并调用[self autorelease]来释放-alertView中的上下文对象:didDismissWithButtonIndex:。

The trouble is releasing memory. I set alertView.delegate to nil and call [self autorelease] to free the context object in -alertView:didDismissWithButtonIndex:.

问题是 :我自己造成了什么问题?我怀疑自己是为了一个微妙的内存错误。

THE QUESTION IS: What problems am I causing myself? I have a suspicion that I'm setting myself up for a subtle memory error.

这是一个只支持-alertView的简单版本:clickedButtonAtIndex:

Here is the simple version which only supports -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];
}



接口



Interface

@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

@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 保存到对象。

You can use the concept of associated objects. Using the functions objc_setAssociatedObject() and objc_getAssociatedObject(). You can use these properties to essentially add a new property, in your case to hold an NSDictionary, to an object through a category.

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

Here is an example of a UIAlertView category. These files should be compiled without ARC, -fno-objc-arc flag set if the project is using 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: a UIAlertViewDelegate 是否使用ARC。

SomeViewController.m: a UIAlertViewDelegate using ARC or not.

-(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的OK按钮时,你会看到:

When you press the alertview's OK button you will see:

userInfo:{
    Greeting = Hello;
}

几个笔记:

1)确保关联类型与属性声明匹配,以便事物按预期运行。

1) Make sure the association type matches the property declaration so things behave as expected.

2)你可能不应该使用属性/关联的userInfo 因为Apple可能决定将 userInfo 属性添加到 UIAlertView 将来。

2) You probably shouldn't use userInfo for the property/association since Apple may well decide to add a userInfo property to UIAlertView in the future.

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

必须平衡隐含的 alloc 保留此行:委托:[[WantAlertViewContext alloc] initWithDelegate:self context:userInfo] 。您可以通过在最终 UIAlertView 委托方法中调用 [self autorelease]; 来实现此平衡。

It is imperative that you balance your implicit alloc retain from this line: delegate:[[WantAlertViewContext alloc] initWithDelegate:self context:userInfo]. You achieve this balance by calling [self autorelease]; in the final UIAlertView delegate method.

当然,这确实是错的。主要是因为在看这个时没有办法乍一看它看起来像内存管理错误。但有一种简单的方法可以避免您正在创建的受控泄漏API;让 WantAlertViewContext 的实例明确保留自己。例如:

Granted, this does feel wrong. Mostly because there is no way when looking at this that it doesn't at first blush look like memory mis-management. But there is one simple way to avoid this "controlled leak" API you are creating; Have the instance of WantAlertViewContext explicitly retain itself. For example:

-(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
}

现在你的班级有一些内在的和谐。我说一些,因为这仍然不完美。例如,如果实例永远不是警报视图委托,则永远不会释放它。它仍然只是一个半控制的内存泄漏。

Now your class has some internal harmony. I say some because this is still not perfect. For example, if an instance is never an alert-view delegate it will never be released. It is still just a "semi-controlled" memory leak.

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

Anyway, now your instantiation call can look more logical:

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

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

I think that this particular design pattern is fraught with danger. If you do end up using it keep a close eye on it.

这篇关于使用用户提供的上下文和[self autorelease]的UIAlertView的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆