【问题标题】:ARC ViewController gets deallocatedARC ViewController 被释放
【发布时间】:2014-01-29 18:08:12
【问题描述】:

我有一个显示按钮的视图控制器。当我单击按钮时,需要调用相应的选择器。但是,使用 ARC 时,应用程序因 EXC_BAD_ACCESS 消息而崩溃。

-(IBAction)reseauPushed:(id)sender{
  self.reseauVC = [[ReseauVCIpad alloc]initWithNibName:@"ReseauVCIpad" bundle:nil];
  [self.viewCenter addSubview:self.reseauVC.view];
}

  @property (strong, nonatomic) ReseauVCIpad *reseauVC;

和崩溃日志:

 -[ReseauVCIpad performSelector:withObject:withObject:]: message sent to deallocated instance

我使用 ARC。 按钮动作:

-(IBAction)helloPushed:(id)sender{
   NSLog("hello);
}

【问题讨论】:

  • 请问可以添加相关代码吗?什么时候实例化 reseauVC,点击按钮时执行什么动作?
  • 也许之前被 self.reseauVC 引用的对象被释放并得到了这个调用?
  • 我今天遇到了类似的问题,ARC 认为你不需要这些对象并减少引用计数,所以当你点击一个按钮时,它会向释放的对象发送消息
  • 我知道,但是我怎么能对 ARC 说我需要这个对象呢?
  • 这看起来像 stackoverflow.com/questions/9390348/… 的副本,只是您已经在视图控制器上使用了强键,因此该问题的接受答案对您不起作用。

标签: ios automatic-ref-counting


【解决方案1】:

这个ReseauVCIpad 视图控制器显然正在以某种方式被释放。要么您不小心将self.reseauVC 设置为nil,或者更可能的是,父视图控制器本身以某种方式被释放。你有没有机会为前面的任何视图控制器使用这种addSubview 技术?如果没有,你是如何实例化根视图控制器的?

要诊断问题出在哪里,我建议您将dealloc 方法添加到所有各种视图控制器中,以便您可以确认是否有任何过早地被释放。 (设置断点或放入 NSLog 语句。)我敢打赌你会看到 ReseauVCIpad 的父级被释放,这反过来又允许 ReseauVCIpad 本身被释放。


顺便说一句,正如其他人所指出的,这个问题的典型答案是确保您正在执行适当的包含调用(如下所示),或者如果这个子视图控制器占据了整个屏幕,您应该只是推动它或模态地呈现它。很明显,你有一个strongReseauVCIpad 的引用,所以缺乏遏制调用并不是ReseauVCIpad 本身问题的根源(尽管我想知道你是否在做这个addSubview 技巧而没有遏制调用ReseauVCIpad 的一个或多个父视图控制器)。

但是无论如何,您仍然应该进行这些包含调用(或进行适当的模态/推送转换),以确保您的视图控制器层次结构与您的视图层次结构保持同步(请参阅 WWDC 2011 视频 Implementing UIViewController Containment 以了解关于为什么这很重要)。添加带有自己的控制器的子视图的适当包含调用至少如下:

- (IBAction)reseauPushed:(id)sender
{
    self.reseauVC = [[ReseauVCIpad alloc]initWithNibName:@"ReseauVCIpad" bundle:nil];
    [self addChildViewController:self.reseauVC];
    [self.viewCenter addSubview:self.reseauVC.view];
    [self.reseauVC didMoveToParentViewController:self];
}

有关更详细的说明,请参阅我上面引用的视频,或参阅 iOS 视图控制器编程指南的Creating Custom Container View Controllers 部分。

当你想移除它时,你也应该在那里进行适当的收容调用:

- (void)removeReseau
{
    [self.reseauVC willMoveToParentViewController:nil];
    [self.reseauVC.view removeFromSuperview];
    [self.reseauVC removeFromParentViewController];
    self.reseau = nil;
}

这通常解决了这个问题(子视图控制器被释放)。它不会解决您的reseauVC 问题(因为您已经有很强的参考),但是(a)无论您使用视图控制器做什么addSubview,您都应该这样做; (b) 如果您在其他地方做 addSubview 而不保持强参考,我会向您展示该模式。

【讨论】:

    【解决方案2】:

    几件事。除非您设置父/子视图控制器关系,否则不应将一个视图控制器的内容视图添加到另一个视图控制器。这是在 iOS 5 中添加的,并在 iOS 6 中进行了扩展(可能在 iOS 7 中进一步扩展......)查看 addChildViewController:、removeFromParentViewController、isMovingToParentViewController 和 didMoveToParentViewController 等方法:

    设置父/子视图控制器关系的最简单方法是使用故事板(需要 iOS 5)和嵌入转场。 (我相信是在 iOS 6 中添加的)。这负责为您设置父/子视图控制器关系的所有内务处理。

    您的第二个视图控制器被保存到一个强属性,所以我不清楚它为什么被释放。我也不清楚对 performSelector:withObject:withObject: 的调用来自何处。哪个源代码行崩溃了,您是否在任何地方的代码中使用 performSelector:withObject:withObject: ?

    【讨论】:

    • 可能崩溃发生在按钮点击操作上
    • 不,我没有使用它,崩溃发生在按钮点击操作上。
    猜你喜欢
    • 2012-03-12
    • 2011-06-01
    • 2013-08-25
    • 1970-01-01
    • 2012-02-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多