Popover 控制器在 iOS 8 中被销毁(无)

Popover controller got destroyed (nil) in iOS 8

在 iOS 7 中,我曾经在我的视图控制器(显示在弹出窗口中)中定义对弹出窗口控制器的弱引用。为了以编程方式关闭弹出窗口,我使用了对弹出窗口控制器的引用。另外,我定义了 popover 控制器的委托以跟踪关闭事件(popoverControllerShouldDismissPopover 等)。

在 iOS 8 它停止工作。调查表明,弱参考点指向 nil 之后的某个点。委托也停止工作(据我所知,这是因为委托是在弹出窗口控制器中定义的,在弹出窗口显示后出于某种原因在 iOS 8 中被销毁)。

问题已通过将 属性 更改为 strong 参考来解决。 对于一些弹出窗口(我有一堆)我不得不添加强引用只是为了让 popoverController 保持活动状态,因为我需要 delegate 才能工作。这很明显是黑客攻击。我添加了 属性,我真的不需要也不用。

能否请您澄清一下这种方法是否正确。我担心的是强引用可能会导致内存泄漏。此外,我不太明白为什么 popoverController 在 iOS 8 中被销毁,而 popover 仍在屏幕上。

这是我的视图控制器 属性。将 weak 更改为 strong 后开始在 iOS 下正常工作 8:

@interface TFDSuggestionViewController : UIViewController
...
@property (weak, nonatomic) UIPopoverController *myPopoverController;
...
@end

这就是我在调用视图控制器时为 属性 和委托 prepareForSegue 方法赋值的方式:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.identifier isEqualToString:@"suggestions"]) {
        TFDSuggestionViewController *suggController = ((TFDSuggestionViewController *)[segue destinationViewController]);
        suggController.myPopoverController = ((UIStoryboardPopoverSegue *)segue).popoverController;
        ((UIStoryboardPopoverSegue *)segue).popoverController.delegate = self;
    }
} 

谢谢您的指教!

在手动内存管理的过去,有一种叫做引用计数的东西。它本质上是一个对象被其他对象或应用程序保留(强引用)的次数。在最近的 ARC(自动引用计数)中,我们不再需要执行 [object retain][object release]。这些动作由编译器为我们处理。

现在说说你的情况。弱引用不会增加您引用的对象的引用计数。所以如果你在一个范围内创建一个对象,给它分配一个弱引用,然后离开这个范围你的对象的引用计数是 0.

-(void)SomeMethod
{
    ClassObject *object = [[ClassObject alloc] init];
    //object's internal reference count is now 1

    self.myPopoverController = object;
    //Since myPopoverController is a weak reference, object still has reference count of 1

    //Some other code that does things and stuff.
}
//We just closed the scope, so object's reference count is now 0
//ARC is free to release the object to free it's memory, causing any
//weak references to return nil

在上面的示例中,它显示了一个非常简单的对象生命周期。一旦了解了生命周期,您就会明白为什么弱引用在这种情况下对您绝对没有好处。

至于为什么它在 iOS7 中起作用而不在 iOS8 中起作用,我唯一的答案是 iOS8 在垃圾收集方面可能更有效。如果您 运行 它在 iOS7 中出现一百万次,我相信您至少会发现一个发生完全相同问题的示例。这是代码中的一个缺陷,新的 OS 变得更加普遍。

如果您希望该对象保持活动状态,您至少需要对它有一个强引用。唯一的预防措施是,当您调用 dismiss 时,您应该取消强引用。那么应该没有不利的内存问题需要解决。

还有一点很重要。 UIPopoverController 与屏幕上显示的对象不同。屏幕上可见的是 UIPopoverController.view。视图仍由视图层次结构保留,但控制器需要由您保留以使其不被释放。一旦 UIPopoverController 被释放,视图的委托将为 nil,因为 view.delegate 也是一个弱引用。

研究对象生命周期。随着 OS 在内存处理方面变得越来越高效,它将帮助您避免将来肯定会出现的垃圾收集问题。