如果视图被取消,请单击UIAlertView崩溃应用程序

时间:2010-10-14 23:04:07

标签: iphone cocoa-touch uiviewcontroller uialertview dismiss

如果发生错误,则会显示UIAlertView。但与此同时,调用UIAlertView的观点已经被驳回(因此被释放)。如果用户单击确定,则应用程序崩溃,因为已发送到已发布实例的消息。这会导致您的应用崩溃:

UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"test" message:@"test" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
[alertView show];
[alertView release];
alertView = nil;
[self.navigationController popViewControllerAnimated:YES];

我认为UIAlertView是一个独立单位。但似乎并非如此。有没有办法可以避免应用程序崩溃(除了不解除视图)?

6 个答案:

答案 0 :(得分:10)

UIAlertView被解雇时调用委托,所以在你的情况下:

delegate:self

代理不会被保留,就像添加到数组中的对象一样,或者是子视图。所以在你的情况下,当你打电话:

[self.navigationController popViewControllerAnimated:YES];

self最有可能被释放,当用户解除警报时,会调用self,但已被解除警告,因此不再存在。

检查此问题的一种简单方法是在NSLog(@"I'm gone");的{​​{1}}方法中添加记录器语句,例如self,如果已运行,则表示您知道dealloc不再存在,发送给它的任何消息都会导致崩溃。

答案 1 :(得分:5)

使UIAlertView成为视图控制器的保留属性,以便您可以在dealloc中引用它,然后在取消分配视图控制器时将警报视图的委托设置为nil。

请务必在解除保留警报视图并取消删除后正确释放保留警报视图。

例如:

@interface MyViewController : UIViewController <UIAlertViewDelegate> {
    UIAlertView *alertView;
}

@property (nonatomic, retain) UIAlertView *alertView;



@implementation MyViewController

@synthesize alertView;

- (void)showAlert {
    if (alertView) {
        // if for some reason the code can trigger more alertviews before
        // the user has dismissed prior alerts, make sure we only let one of
        // them actually keep us as a delegate just to keep things simple
        // and manageable. if you really need to be able to issue multiple
        // alert views and be able to handle their delegate callbacks,
        // you'll have to keep them in an array!
        [alertView setDelegate:nil];
        self.alertView = nil;
    }
    self.alertView = [[[UIAlertView alloc]
                       initWithTitle:@"Error"
                       message:@"Something went wrong"
                       delegate:self
                       cancelButtonTitle:@"Cancel"
                       otherButtonTitles:@"Retry",nil] autorelease];
    [alertView show];
}

- (void)alertView:(UIAlertView *)alertViewParam didDismissWithButtonIndex:(NSInteger)buttonIndex {
    self.alertView = nil; // release it
    // do something...
}

- (void)dealloc {
    [alertView setDelegate:nil]; // this prevents the crash in the event that the alertview is still showing.
    self.alertView = nil; // release it
    [super dealloc];
}

此处的缺点是,当用户解除警报视图时,您将无法处理警报视图的回调。但是,由于你的控制器已经消失/释放,大概你不需要。如果这样做,则必须将警报视图的委托设置为将持续存在的内容。

答案 2 :(得分:1)

如果UIAlertView对象可以在应用程序的任何地方使用,而不仅仅是在当前视图中,那么将其保留在应用程序中任何位置可用的内容中,或者在整个可能的视图堆栈下保留一些持久的根视图控制器,或应用代表。

添加了:

此顶级对象也可以保留警报视图的委托,直到需要完成后(在警报视图解除之后)。

答案 3 :(得分:1)

(人们可能会怀疑我多年来一直在回答这个问题,但它可能对其他人有所帮助)

我猜你的问题在于弹出视图控制器,你正在显示警报视图,同时尝试将用户导航回视图。我建议你遵循这里的分层方法,即:< / p>

首先将您的警报视图声明为全局对象,即

@property(nonatomic,retain) UIAlertView *sampleAlert;

现在编写警报视图显示代码,例如:

-(IBAction)buttonClicked:(id)sender
{
  self.sampleAlert = [[UIAlertView alloc] initWithTitle:@"test" message:@"test" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
  [sampleAlert show];
  [sampleAlert release];
}

当按下“确定”按钮时,最后尝试将用户导航到所需的视图,即。你需要使用alertView didDismissWithButtonIndex方法,即

- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex 
{
   if(alertView == sampleAlert)
   {
     [self.navigationController popViewControllerAnimated:YES];
   }
}

请注意,如果您有多个按钮的警报视图,您还需要检查按钮索引以区分操作,即。检查使用

if(alertView == sampleAlert && buttonIndex == 0)
{
  //Do your stuff
}
else
{
  //Do something else
}

这肯定会避免应用程序崩溃,谢谢:)

答案 4 :(得分:1)

对我来说更简单的方法是在数组中保存所有警报视图,并在取消分配父视图时枚举alertViews数组并将委托指定为nil。这将确保忽略触摸事件并且app将起作用。

// ARC world

@property (strong, nonatomic) NSMutableArray *alertViews;

- (void)dealloc
{
    [self.alertViews makeObjectsPerformSelector:@selector(setDelegate:) withObject:nil];
}

答案 5 :(得分:-2)

确保您正在实施UIAlertViewDelegate协议。 如果您不关心何时取消警报,则只需将委托作为nil进行初始化。

UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"test" message:@"test" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];