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 在内存处理方面变得越来越高效,它将帮助您避免将来肯定会出现的垃圾收集问题。
在 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 在内存处理方面变得越来越高效,它将帮助您避免将来肯定会出现的垃圾收集问题。