2010-10-14 3 views
4

При возникновении ошибки отображается UIAlertView. Но тем временем вид, на который были вызваны 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 является самостоятельным структурным подразделением. Но, похоже, это не так. Есть ли способ избежать сбоя приложения (за исключением того, что вы не отклоняете представление)?

ответ

-2

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

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

Я внедрил для этого оповещения протокол UIAlertViewDelegate. Кажется, что нет другого способа, кроме предоставления только кнопки «ОК» и установки делегата на нуль. Я попробую. – testing

+0

Это неправильный ответ. Ответ SooDesuNe верен. Вам нужно либо не установить делегат, либо убедиться, что UNSET это, если делегат будет выпущен. – DougW

10

Делегат вызывается, когда UIAlertView освобождается, так что в вашем случае:

delegate:self 

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

[self.navigationController popViewControllerAnimated:YES]; 

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

Простой способ проверить это поставить регистратор заявление, как NSLog(@"I'm gone"); в dealloc методы self «s, если он побежал, то вы знаете, ваш self не вокруг больше, и все сообщения, отправленные на него вызовут авария.

+1

Хорошее объяснение. Но что я могу сделать против этого? – testing

+0

У вас есть два варианта: 1) выбрать другой делегат или 2) сохранить 'self', сохраненный каким-либо другим объектом (т. Е. Из другого объекта [ссылка-на-что-бы-вызывать-само-сохранение]), не зная, что вы делаете в методах делегата, трудно сказать, что лучше. Если вы не используете методы делегата, команда 'nil' будет делегатом. – SooDesuNe

+2

. Я предлагаю другой вариант в моем ответе ниже: просто отмените делегат, когда представление будет освобождено. – Yetanotherjosh

1

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

Добавлено:

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

+0

UIAlertView сохраняется, когда вы вызываете шоу на нем. – aegzorz

+0

@aegzorz: сохранилось? – hotpaw2

+0

Более важный вопрос: кто сохраняет делегат представления предупреждения? Это должно быть устойчивым. – hotpaw2

5

Сделать 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]; 
} 

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

+0

Awesome. Прекрасно работает. В дополнение к вашему предложению, я добавил [alertView rejectWithClickedButtonIndex: 0 анимированный: ДА]; к первой строке dealloc, так что alertView программно удален. – JeffB6688

+0

Здравствуйте, выше код работает нормально, когда вы показываете предупреждение в том же контроллере. Но когда вы переходите на другую страницу и возвращаетесь на эту страницу, и снова пытаетесь показать предупреждение, показывать предупреждение, но его методы делегатов не звонят. Он не отклоняется автоматически. Когда вы нажимаете кнопку «Отмена», она увольняется.[alertView rejectWithClickedButtonIndex: 0 анимированный: ДА]; эта строка не работает, когда вы ожидаете завершения какой-либо задачи, а затем увольтете ее. –

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

Наконец попытаться перейти пользователя к требуемому виду при нажатии на кнопку «Ok», то есть. вам необходимо использовать метод 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

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

// ARC world 

@property (strong, nonatomic) NSMutableArray *alertViews; 

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

отлично работает – ManicMonkOnMac

Смежные вопросы