5

UIAlertView如果发生错误,将显示A。但与此同时,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是一个独立的单位。但似乎并非如此。有没有办法避免应用程序崩溃(除了不关闭视图)?

4

6 回答 6

10

UIAlertView被解雇时会调用委托,因此在您的情况下:

delegate:self

不保留委托,就像添加到数组中的对象或子视图一样。所以在你的情况下,当你打电话时:

[self.navigationController popViewControllerAnimated:YES];

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

一个简单的检查方法是放置一个 logger 语句,就像NSLog(@"I'm gone");inselfdealloc方法一样,如果它运行了,那么你就知道你self的不在了,任何发送给它的消息都会导致崩溃。

于 2010-10-14T23:24:14.330 回答
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];
}

这里的缺点是当用户关闭它时,您将无法处理警报视图的回调。但是,由于您的控制器已经消失/发布,因此您可能不需要这样做。如果这样做,则必须将警报视图的委托设置为将持续存在的内容。

于 2012-03-22T06:09:06.297 回答
1

对我有用的更简单的方法是将所有警报视图保存在一个数组中,当父视图被释放时,枚举 alertViews 数组并将委托分配给 nil。这将确保触摸事件被忽略并且应用程序将正常运行。

// ARC world

@property (strong, nonatomic) NSMutableArray *alertViews;

- (void)dealloc
{
    [self.alertViews makeObjectsPerformSelector:@selector(setDelegate:) withObject:nil];
}
于 2013-10-03T22:15:26.047 回答
1

(人们可能想知道我回答这个问题迟了很多年,但这可能对其他人有帮助)

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

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

@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];
}

最后尝试在按下“确定”按钮时将用户导航到所需的视图,即您需要使用 alertViewdidDismissWithButtonIndex方法,即

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

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

于 2013-09-06T08:16:20.247 回答
1

如果 UIAlertView 对象可以在应用程序的任何地方使用,而不仅仅是在当前视图上,那么将其保留在应用程序任何地方都可用的东西中,或者是整个可能的视图堆栈下的某个持久根视图控制器,或者应用委托。

添加:

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

于 2010-10-14T23:24:18.340 回答
-2

确保您正在实施该UIAlertViewDelegate协议。如果您不关心何时解除警报,只需使用 delegate as 进行初始化nil

UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"test" message:@"test" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
于 2010-10-14T23:16:00.513 回答