如果视图被关闭,单击 UIAlertView 会使应用程序崩溃

发布于 2024-09-27 16:41:40 字数 493 浏览 9 评论 0原文

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

A UIAlertView is displayed if an error occurs. But in the meantime the view on which the UIAlertView were called has been dismissed (and therefore released). If the user clicks on OK the app crashes because a message to a released instance is sent. This will cause your app crashing:

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

I thought the UIAlertView is an independent unit. But it seems it isn't. Is there a way how I could avoid the app crashing (except not dismissing the view)?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

烟若柳尘 2024-10-04 16:41:40

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

delegate:self

不会保留委托,就像添加到数组中的对象或子视图一样。因此,在您的情况下,当您调用:

[self.navigationController popViewControllerAnimated:YES];

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

检查这一点的一个简单方法是在 selfdeallocNSLog(@"I'm gone"); > 方法,如果它运行了,那么你就知道你的 self 已经不存在了,发送给它的任何消息都会导致崩溃。

The delegate is called when the UIAlertView is dismissed, so in your case:

delegate:self

Delegates are not retained, like an object added to an array, or a subview would be. So in your case, when you call:

[self.navigationController popViewControllerAnimated:YES];

self is most likely being released, and when the the user dismisses the alert, self is called, but has been dealloc'd so it no longer exists.

An easy way to check this is to put a logger statement, like NSLog(@"I'm gone"); in self's dealloc method, if it's ran, then you know your self isn't around anymore, and any messages sent to it will cause a crash.

辞取 2024-10-04 16:41:40

将 UIAlertView 设为视图控制器的保留属性,以便您可以在释放中引用它,然后在释放视图控制器时将警报视图的委托设置为 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];
}

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

Make the UIAlertView a retained property of your view controller so that you can refer to it in your dealloc, then set the alert view's delegate to nil when the view controller is deallocated.

Be sure to properly release the retained alert view once it's been dismissed and on dealloc.

For instance:

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

The downside here is that you will not be able to handle the alert view's callback when the user dismisses it. However, since your controller is already gone/released, presumably you don't need to. If you do, you have to set the alert view's delegate to something that will persist.

同尘 2024-10-04 16:41:40

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

添加:

此顶级对象还可以保留警报视图的委托,直到需要它为止(警报视图关闭后)。

If the UIAlertView object is to be usable from anywhere in the app, not just on the current view, then retain it inside something that is available from anywhere in the app, either some persistant root view controller under the entire possible view stack, or the app delegate.

Added:

This top level object can also retain the alert view's delegate until after it's done being needed (after alert view dismissal).

黑白记忆 2024-10-04 16:41:40

(人们可能想知道我回答这个问题已经晚了好几年,但这可能对其他人有帮助)

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

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

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

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

(People might wonder I am late by years in answering this question,but it might help someone else)

I guess your problem lies some where in popping the view controller,you are displaying the alert view and at the same time trying to navigate the user back to a view.I would recommend you to follow a hierarchal approach here i.e.:

First of all declare your alert view as a global object,i.e.

@property(nonatomic,retain) UIAlertView *sampleAlert;

Now write your alert view display code where ever desired,say for instance:

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

Finally try to navigate the user to the desired view when the "Ok" button is pressed,i.e. you need to make use of alertView didDismissWithButtonIndex method,i.e.

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

Please note that if you have alert view with multiple buttons,you also need to check for button index for distinguishing actions,i.e. check using

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

This will definitely avoid application crash,thanks :)

深海夜未眠 2024-10-04 16:41:40

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

// ARC world

@property (strong, nonatomic) NSMutableArray *alertViews;

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

Easier way that worked for me is to hold all the alert views in a Array and when the parent view is deallocated enumerate alertViews array and assign the delegate to nil. This will ensure that the touch event is ignored and app will function.

// ARC world

@property (strong, nonatomic) NSMutableArray *alertViews;

- (void)dealloc
{
    [self.alertViews makeObjectsPerformSelector:@selector(setDelegate:) withObject:nil];
}
小苏打饼 2024-10-04 16:41:40

确保您正在实现 UIAlertViewDelegate 协议。
如果您不关心警报何时解除,只需将委托初始化为nil

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

Make sure you are implementing the UIAlertViewDelegate protocol.
If you don't care about when the alert is dismissed just init with delegate as nil.

UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"test" message:@"test" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文