iOS如何决定哪些对象发送didReceiveMemoryWarning消息?

时间:2011-06-18 09:25:41

标签: iphone objective-c ios cocoa-touch

我正在开发一个iPhone应用程序,在该应用程序中,动态添加和删除主UIWindow中的许多UIView。

在模拟器中模拟低内存错误时,我发现并非所有视图控制器都会收到didReceiveMemoryWarning通知。不幸的是,这些是最能从实施此方法中受益的控制器。

我似乎无法找到关于调用方法的位置和方式的好信息。我已经读过提到它被发送到“所有UIViewControllers”,但事实并非如此。在收到通知的其中一个类中添加断点也不是特别有启发性。

这是一个复杂的项目,但添加这些视图的方法是:

- (void) showMyView
{
  if(!myViewController){
    myViewController = [[MyViewController alloc]init];
    [window addSubview:myViewController.view];
  }
}

MyViewController是另一个类MySuperViewController的子类,它本身是UIViewController的子类。这些类都没有相应的NIB;视图层次结构以编程方式创建。

我正在寻找有关如何诊断问题的指示。

4 个答案:

答案 0 :(得分:3)

当您直接使用视图控制器的.view时,视图控制器很可能不会收到很多通知,因为它不是使用视图控制器的正确方法。 UIWindow是特例,因为窗口可以自动知道视图的控制器并正确地将消息定向到控制器。

但是,当您从UIWindow分离视图时,视图控制器也会分离,不再由UIWindow管理。我认为这是问题的根源。

我建议您添加导航控制器或标签栏控制器作为根视图控制器,并使用该视图控制器功能在您的子控制器之间切换。请注意,切换时不应删除视图控制器,以便他们能够正确接收消息。

如果视图控制器的初始化很简单并且不会消耗太多时间,您可能还会考虑在未使用时释放视图控制器。

答案 1 :(得分:2)

您的代码中的某处可能正在执行以下操作:

[[NSNotificationCenter defaultCenter] removeObserver:self];

唯一安全的地方是-dealloc

在其他任何地方,您都应该指定要取消注册的通知(如果您注册与superlcass相同的通知,这仍然可能会中断)。

答案 2 :(得分:1)

来自文档

  

默认实现   [didReceiveMemoryWarning]检查   查看视图控制器是否可以安全   释放它的观点。如果这是可能的   视图本身没有   superview 也可以重新加载   从nib文件或使用自定义   loadView方法。

当模拟记忆警告“发生”/时,会调用此方法。当内存不足时,系统可能会发布notification,并且视图控制器会通过调用didReceiveMemoryWarning来响应通知。

如果不覆盖该方法,则调用默认实现(如上所述)。内存中的所有视图控制器接收内存警告并调用此方法。如果释放视图不安全,他们就不会做任何事情。

在带导航控制器的简单测试应用程序中,在当前视图控制器和先前显示的控制器中,都会调用didReceiveMemoryWarning。我不知道NSNotificationCenter如何正常工作,但它知道谁注册了UIApplicationDidReceiveMemoryWarningNotification。它可能设置如下:

[[NSNotificationCenter defaultCenter] addObserver:self 
                                         selector:@selector(didReceiveMemoryWarning)
                                             name:UIApplicationDidReceiveMemoryWarningNotification  
                                           object:nil];

有关详细信息,请查看UIViewController Class Reference

中的“内存管理”部分

答案 3 :(得分:1)

我输入了这个问题,寻找处理记忆警告的正确观察者。对于使用swift的用户,可以注册如下:

NSNotificationCenter.defaultCenter().addObserver(self, selector: "didReceiveMemoryWarning:", name:UIApplicationDidReceiveMemoryWarningNotification, object: nil)

使用回调方法:

func didReceiveMemoryWarning(notification: NSNotification){
    //Action take on Notification
}

另外,请确保您的自定义类继承自NSObject,否则您将收到此错误:

… does not implement methodSignatureForSelector: — trouble ahead