在Cocoa应用程序运行时生命周期中,会有一个或多个nib文件被加载,而且它们所包含的对象会被解压。当不再需要它们时,谁来负责释放这些对象取决于您在哪种平台进行开发,而且,如果是在Mac OS X的话,还取决于您的file’s Owner继承自哪个类。
关于nib文件及其内存管理语义的基本讨论,以及与nib相关的术语的定义,比如插座对象,file’s Owner和顶层对象,请参考资源编程指南中的“Nib文件”一节。
插座对象当一个nib文件被加载且插座对象被建立的时候,如果存取方法(在Mac OS X和iOS上都)存在,则nib加载机制一定会使用存取方法。因此,无论您在哪个平台上进行开发,一般情况下,您都应该使用Objective-C的属性声明功能声明插座对象。
声明插座对象的一般形式应该是:
@property (attributes) IBOutlet UserInterfaceElementClass *anOutlet; |
插座对象的行为取决于平台的类型(请参考“Mac OS X”和“iOS”),因此,实际的声明会有所不同:
对于Mac OS X,您应该使用:
对于iOS,您应该使用:
接下来,您应该做的是合成相应的存取方法,或者是根据声明实现这些方法,(在iOS平台)还要在dealloc
中释放相应的变量。
如果您使用现代运行时并合成实例变量,这种模式同样适用,因此它能够在所有情况下保持一致性。
Mac OS X 在默认情况下,nib文件的File’s Owner负责释放nib文件中的顶层对象和nib中的对象创建的所有非对象资源。对象图中的根对象的释放会促使所有依赖它的对象也被释放。对应用程序的主nib文件(其中包含应用程序菜单和其他可能的项目)来说,它的“文件所有者”是全局应用程序对象NSApp
。然而,当Cocoa应用程序终止时,主nib中的顶层对象不会因为NSApp
被回收(请参考“回收对象”)而自动获得dealloc
消息。换句话说,即使是在主nib文件中,您也必须管理顶层对象的内存。
应用程序套件提供了一系列功能来帮助您确保nib对象能够被正确地释放:
NSWindow
对象(包括面板)有一项isReleaseDWhenClosed
属性,如果该属性被设为YES
,则窗口会在关闭的时候释放它自己(和它的视图层次中所有相关的对象)。在Interface Builder中,您可以通过勾选检视器的属性面板上的“在关闭时释放”复选框来设置此选项。
如果nib文件的“文件所有者”是一个NSWindowController
对象(它是基于文档的应用程序中的文档默认nib—前面介绍过,NSdocument
负责管理NSWindowController
实例),它会自动销毁它所管理的窗口。
因此,在一般情况下,您负责释放nib文件中的顶层对象。但实际上,如果您的nib文件的所有者是一个NSWindowController
实例,则它会为您释放顶层对象。如果您的某个对象加载了nib本身(而且它的所有者不是NSWindowController
实例),则您可以为每一个顶层对象定义插座对象,以便您可以在适当的时候使用这些引用释放它们。如果您不希望为所有的顶层对象定义插座对象,那么您可以使用NSNib
类的instantiateNibWithOwner:topLevelObjects:
方法来获得一个包含nib文件顶层对象的数组。
当您考虑到应用程序的各种类型时,销毁nib对象的责任问题就变得更清晰了。大多数Cocoa应用程序归属于两类:单一窗口应用程序和基于文档的应用程序。在这两种情况下,系统会在一定程度上为您自动处理nib对象的内存管理。在单一窗口应用程序中,主nib文件中的对象在应用程序的整个运行周期内持续存在,并在应用程序终止时被释放;但是,系统并不保证在应用程序终止时自动地对主nib文件中的对象调用dealloc
。在基于文档的应用程序中,每一个文档窗口都由一个NSWindowController
对象管理,该对象处理文档nib文件的内存管理。
有些应用程序可能具有更复杂的nib文件和顶层对象的分布。例如,应用程序可能有多个nib文件,并带有多个窗口控制器,可加载的面板和检视器。但是,在大多数情况下,如果您使用NSWindowController
对象来管理窗口和面板,或者如果您设置了“在关闭时释放”这一窗口属性,那么系统会为您自动处理大部分的内存管理。如果您决定不使用窗口控制器,也不想设置“在关闭时释放”属性,则您应该在窗口关闭时显式地释放您的nib文件的窗口和其他顶层对象。此外,如果您的应用程序使用检视器面板,那么(在延迟加载之后)该面板通常应该在整个应用程序生命周期内持续存在—没有必要销毁检视器和它的资源。
当nib文件中的对象被创建时,它们的保留计数为1,而且随后它们会被自动释放。由于重建了对象层次结构,UIKit会使用setValue:forKey:
重新建立对象之间的连接,setValue:forKey:
使用现有的setter方法,如果没有setter方法可用,那么它会默认保留这个对象。这就意味着(假设您遵循“插座对象”中所示的模式)具有插座对象的任何对象都保持有效。但是,如果存在您没有存储在插座对象中的顶层对象,则您必须保留loadNibNamed:owner:options:
方法返回的数组或数组中的对象,以防止这些对象过早地被释放。.
当视图控制器收到内存警告(didReceiveMemoryWarning
)的时候,它应该释放那些当前不需要的,和那些如果有需要可以稍后重新创建的资源的所有权。其中一种资源就是视图控制器的视图本身。如果它没有父视图,则该视图应该被销毁(在它的dIDReceiveMemoryWarning
实现中,UIVIEwController
调用[self setVIEw:nil]
)。
但是,由于nib文件中的元素的插座对象通常会被保留(见“插座对象”),因此,即使主视图被销毁,如果没有采取任何进一步的行动,插座对象也不会被销毁。这并不是其本身的问题—如果当主视图被重新载入时,它们只是被简单地替换掉—但这确实意味着,dIDReceiveMemoryWarning
的效果被削弱了。为了确保您正确地释放插座对象的所有权,在您的自定义视图控制器类中,您可以实现viewDidUnload
来调用您的存取方法,以便将插座对象设置为nil
。
注意:在iOS 3.0版本之前,vIEwDIDUnload
方法是不可用的。相反,您应该在setVIEw:
中将插座对象设置为nil
,正如该例所示:
UIVIEwController
中的 dealloc
的一个实现细节,您还应该在 dealloc
中将插座对象变量设置为 nil
: - (voID)dealloc {
以上是内存溢出为你收集整理的Nib 对象的内存管理全部内容,希望文章能够帮你解决Nib 对象的内存管理所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)