Нажмите на приложение сбоев UIAlertView, если просмотр закрыт - PullRequest
4 голосов
/ 15 октября 2010

A 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 ]

10 голосов
/ 15 октября 2010

Делегат вызывается при отклонении UIAlertView, поэтому в вашем случае:

delegate:self

Делегаты не сохраняются, как объект, добавленный в массив, или подпредставление будет. Так и в вашем случае, когда вы звоните:

[self.navigationController popViewControllerAnimated:YES];

self, скорее всего, освобождается, и когда пользователь отклоняет предупреждение, вызывается self, но он был освобожден, поэтому его больше не существует.

Простой способ проверить это - поместить оператор logger, например, NSLog(@"I'm gone"); в self метод *1013*, если он запущен, то вы знаете, что ваш self больше не существует отправленные ему сообщения вызовут сбой.

5 голосов
/ 22 марта 2012

Сделайте UIAlertView сохраненным свойством вашего контроллера представления, чтобы вы могли ссылаться на него в свой dealloc, а затем установите делегат представления оповещения равным нулю, когда контроллер представления освобожден.

Обязательно правильно освободитесохраненное представление оповещения после того, как оно было отклонено и находится на dealloc.

Например:

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

Недостатком является то, что вы не сможете обрабатывать обратный вызов представления оповещения, когда пользователь отклоняетЭто.Однако, так как ваш контроллер уже ушел / выпущен, вероятно, вам не нужно.Если вы это сделаете, вы должны установить делегат представления оповещения на то, что будет сохраняться.

1 голос
/ 04 октября 2013

Более простой способ, который сработал для меня, - это удерживать все представления предупреждений в массиве, а когда родительское представление освобождается, перечислять массив alertViews и присваивать делегату значение nil.Это гарантирует, что сенсорное событие будет проигнорировано, и приложение будет работать.

// ARC world

@property (strong, nonatomic) NSMutableArray *alertViews;

- (void)dealloc
{
    [self.alertViews makeObjectsPerformSelector:@selector(setDelegate:) withObject:nil];
}
1 голос
/ 06 сентября 2013

(Люди могут задаться вопросом, что я на годы опаздываю с ответом на этот вопрос, но это может помочь кому-то еще)

Я полагаю, что ваша проблема кроется в том, что при подключении контроллера представления вы отображаете представление предупреждений и в то же время пытаетесь переместить пользователя обратно к представлению. Я бы порекомендовал вам следовать иерархическому подходу, то есть 1003 *

Прежде всего объявите ваше представление оповещения как глобальный объект, т.е.

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

Это определенно поможет избежать сбоя приложения, спасибо:)

1 голос
/ 15 октября 2010

Если объект UIAlertView можно использовать из любой точки приложения, а не только из текущего представления, сохраните его внутри чего-либо, доступного из любой точки приложения, либо какого-либо постоянного корневого контроллера представления во всем возможном стеке представленияили делегат приложения.

Добавлено:

Этот объект верхнего уровня также может сохранять делегата представления оповещения до тех пор, пока он не будет необходим (после отмены представления оповещения).

0 голосов
/ 15 октября 2010

Убедитесь, что вы используете протокол UIAlertViewDelegate. Если вас не волнует, когда оповещение будет отклонено, просто введите init с делегатом как nil.

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