alertView:didDismissWithButtonIndex: 消息发送到解除分配的实例
Posted
技术标签:
【中文标题】alertView:didDismissWithButtonIndex: 消息发送到解除分配的实例【英文标题】:alertView:didDismissWithButtonIndex: message sent to deallocated instance 【发布时间】:2012-10-30 19:14:12 【问题描述】:这个问题只发生在 ios4.3 上。我正在使用 ARC,我的 Base SDK 是 iOS6。
在我的视图控制器的-viewDidAppear
中,我检查这是否是应用程序第一次启动,如果是,则创建并显示一个 UIAlertView。我将该 UIAlertView 分配给视图控制器上的 strong
属性,并将 self 设置为 UIAlertView 委托。
self.uiAlertView = [[UIAlertView alloc] initWithTitle:@"Welcome!"
message:messageString
delegate:self
cancelButtonTitle:@"OK"
otherButtonTitles:@"View Tutorial Videos", @"Email Support", nil];
当我点击其中一个按钮时,应用程序崩溃并抱怨 -alertView:didDismissWithButtonIndex:
被发送到一个已释放的实例。委托是显示 UIAlertView 的视图控制器。
在应用程序的所有后续启动中,如果 UIAlertView 未显示,则没有问题。视图控制器肯定没有被释放。
如果我显示 UIAlertView 但将委托设置为 nil,则没有问题,应用程序继续工作,因此显然视图控制器没有被释放,因为我可以继续使用它。
发生了什么?这只会导致 iOS4.3 出现问题。
编辑:根据 cmets 中的建议,我在不同的地方添加了更多日志消息。
我发现视图控制器正在被释放,但前提是该视图控制器显示 UIAlertView。究竟是什么会导致视图控制器因为它将自己设置为 UIAlertView 的委托然后显示它而被解除分配?
我的应用程序委托有一个 strong
对视图控制器的引用,所以我绝对没有理由看到视图控制器被释放。
编辑 2:我发现在启动过程中,我的主视图控制器被实例化了两次。第一个是创建 UIAlertView 的那个,那个正在被释放。第二个是我之后能够与之交互的那个,它让我认为视图控制器仍然存在并且可以操作。
但是,我无法弄清楚我的视图控制器会在哪里或为什么会被创建两次。我没有任何用于视图控制器的 alloc/init 语句。它只存在于 MainWindow_iPhone.xib 中。
第一次在我的视图控制器上调用viewDidLoad,上面的栈帧是[UIViewController view]。在我的视图控制器的第二个实例上第二次调用 viewDidLoad 时,上面的堆栈帧是 [UINib instantiateWithOwner:options:]
编辑 3:我已经“解决”了这个问题,但我不明白为什么会发生这种情况。或许你能帮我理解。
在我的 MainWindow_iPhone.xib 中,我创建了根视图控制器并将其分配给我的应用程序委托上的 IBOutlet。相反,我从 xib 中删除了视图控制器,并在 -application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
中的代码中创建了它......问题就消失了。
为什么在 xib 中视图控制器会被创建两次?
【问题讨论】:
您必须显示更多代码,因为您显示的问题似乎是无论 self 是什么,当您单击 OK 按钮时确实已解除分配 但如果我只是不显示 UIAlertView,视图控制器将完美运行并且永远不会被释放。如果我只是注释掉 [self.uiAlertView show];打电话然后它工作。那么什么甚至可能导致当前可见的视图控制器被释放。这没有意义。 如果它只发生在 iOS 4.3 上,它可能是一个错误。让我们找到一种解决方法。首先,尝试 nslog 并检查代理是否设置正确。: NSLog(@"This VC: %@ - Alert Delegate: %@", self, self.uiAlertView.delegate) 在 uiAlertView 分配后立即。显然,在结果中,self 和警报委托应该有相同的实例。如果不一样(例如:self.uiAlertView.delegate 为 nil),直接尝试再次设置:self.uiAlertView.delegate = self;然后再次 nslog 当我在 alloc/init 之后记录委托时,它是正确的。我还设置了一个 GCD 调用以在 3 秒后再次记录它。当我在那之后点击 OK 按钮并得到-[MyViewController alertView:didDismissWithButtonIndex:]: message sent to deallocated instance 0x7b37600
错误.. 错误中的类是 RIGHT 类。因此,它清楚地指向正确的内存位置,并且该视图控制器在那里并且正在工作......但是当 UIAlertView 尝试调用 didDismissWithButtonIndex 时,它认为它已被释放。
我在我的视图控制器上向 dealloc 添加了一条日志消息,它肯定会被调用...但它仅在我显示 UIAlertView 时被调用。怎么回事?显示 UIAlertView 怎么会导致显示视图控制器被释放?
【参考方案1】:
我之前也遇到过这个问题。 alertView:didDismissWithButtonIndex: 在 alertView: clickedButtonAtIndex: 之后调用。您很可能通过执行类似 [self.navigationController popViewControllerAnimated:YES] 的操作在 alertView:clickedButtonAtIndex 中取消分配视图控制器。
UIAlertView 委托分配非弱引用。当委托被释放时,它不会自动设置为 nil。这就是你的代码崩溃的原因。
【讨论】:
【参考方案2】:我修复了这个问题,评论这个方法(或删除它)。
- (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex
NSLog(@"se apreto cancel");
正如 James Wang 所说,didDismissWithButtonIndex 是在 clickedButtonAtIndex 之后调用的,所以我对其进行了评论以避免崩溃。
【讨论】:
以上是关于alertView:didDismissWithButtonIndex: 消息发送到解除分配的实例的主要内容,如果未能解决你的问题,请参考以下文章