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