iPhone开发指南-内存管理

内存管理工作原理

在内存管理的Objective-C代码里,一个Cocoa对象存在于一个生命周期,有明确的阶段。它被创建,初始化,并使用(也就是,其它对象发送消息给它)。它还可能会被保留,拷贝,或压缩,并最终被释放和销毁。下面的讨论以图表形式对一个典型对象的生命周期进行了描述,这里还没有涉及更多的细节。

让我们从后面开始,当垃圾收集被关掉时对象销毁的方式。在此背景下CocoaObjective-C 选择一个自动的,策略驱动的过程来保持对象的存在并在不再被需要的时候销毁它们。

这个过程和策略依赖于引用计数的概念。每个Cocoa对象携带一个整数用来指示对其存在感兴趣的其它对象的数目。这个整数被称为对象的保留数(retain count)(“retain”用来避免和术语“reference”重叠)。 当你创建一个对象时,或者通过一个类工厂方法或者使用alloc allocWithZone: 类方法, Cocoa 做了一些很重要的事情:

·         它设置对象的isa 指针- NSObject 类的唯一公共成员变量-以指向这个对象的类,这样把这个对象集成到运行时视图类层次。(参见对象创建“Object Creation”获取更多信息)

·         它设置对象的保留数(retain count- 一种由运行时管理的隐藏的成员变量- 1。(这里假设一个对象的创建者对其存在感兴趣)

在对象分配后,你一般会设置它的成员变量为一个合理的初始值。 (NSObject 声明init 方法作为这个目的的原形) 这个对象现在已经可以使用了;你可以发送消息给它,把它传递给其他对象,等等。

注意: 因为一个初始化器可以返回一个不是显式声明的那个对象,惯例是嵌套alloc 消息表达式在init 消息里(或者其他初始化器)- 比如:

id anObj = [[MyClass alloc] init];

 

当你释放一个对象- 也就是,发送一个release 消息给它 - NSObject 减少其保留数。如果这个保留数从1变成0,这个对象会被释放。释放分成两个步骤。首先,对象的dealloc 方法被调用来释放成员变量并动态释放分配的内存。然后操作系统销毁对象自身并回收该对象曾经占用的内存。

重要: 你永远不该直接调用一个对象的dealloc 方法。

 

要是你不想一个对象马上消失?如果你在从别处接收到一个对象时给它发送了一个retain 消息,这个对象的保留数(retain count)被增加为2。现在在释放之前需要两个release 消息。2-4 图示了这个相对简化的场景。

Figure 2-4  一个对象的生命周期- 简化视图

 

object_lifecycle_1

当然,在这个场景中,一个对象的创建者不需要保留这个对象。它早就拥有了这个对象。但是如果这个创建者在一个消息中传递这个对象给另外的对象,情况就发生了变化。在一个Objective-C 程序中,一个接收一些其他对象的对象总是假设在其获得的范围内有效。这个接收对象可以发送消息给被接受的对象以及传递给其他对象。这个假设需要发送对象运转并且不会过早的释放这个对象,当一个客户对象有一个指向它的引用时。

如果客户对象想在接收到的对象程序访问范围之外保留它,可以retain - 也就是,发送一个retain 消息给它。保留一个对象增加其保留计数,并由此表达该对象的一个所有权。这个客户对象假设稍后释放该对象的一个职责。如果一个对象的创建者释放它,但是一个客户对象保留了这个相同的对象,这个对象保持存在直到这个客户释放了它。图2-5 说明了这个顺序:

Figure 2-5  保留一个接收到的对象

 

object_lifecycle_2

和保留一个对象相反,你可以通过给它发送一个copy copyWithZone:消息来拷贝它。(很多子类,如果不是大多数,封装了一些采用或符合这个协议的数据)。拷贝一个对象不仅复制它而且常常总是重置它的保留计数为1(参见图2-6)。拷贝可以是浅拷贝也可以是深拷贝,这依赖于这个对象的本质以及它的预期用途。一个深拷贝复制出一个可以承担成员变量相同作用的对象,而浅拷贝仅仅增加这些成员变量的引用。

谈到使用,区别一个copy retain 的是前者声称这个对象的单独使用权;新的拥有者可以改变这个拷贝对象而无须关心它的原始对象。一般而言你拷贝一个对象而不是保留它,当它是一个数值对象- 也就是,一个对象封装了一些基本数据(如整数)。特别是这个对象本身是可变的,比如一个NSMutableString,对于非可变对象,copy retain 可以等同并且也许可以用类似方法来实现。

Figure 2-6  拷贝一个接收到的对象

 

object_lifecycle_3

你也许注意到了这个机制关于管理对象生命周期的一个潜在的问题。创建了一个对象并传递给另外的对象的这个创建者对象并不总是知道什么时候可以安全的释放掉这个被创建出来的对象。有可能在堆栈中有这个对象的多个引用,有一些是创建者对象所不知道的。如果这个创建者对象释放掉这个被创建的对象然后其他对象给这个已销毁对象发送消息的话,程序将崩溃。为了消除这个问题,Cocoa 引入了一个延迟释放的机制叫做autoreleasing

Autoreleasing 使用自释放池(autorelease pools (以NSAutoreleasePool 类定义)。一个自释放池是一个明确定义了范围的对象集合,这个范围标记着最终什么时候释放。自释放池可以被嵌套。当你发送一个 autorelease 消息, 一个该对象的引用被放进最近的自释放池中。它仍然是一个有效的对象,所以其他在自释放池定义范围内的对象可以给它发送消息。当程序执行到范围末尾时,这个池被释放,而且,相应的,池中的所有对象也将被释放(参见图2-7)。如果你在开发一个应用程序你可能不需要建立一个自释放池,因为应用程序工具箱(Application Kit)会自动建立一个范围为应用程序事件周期的自释放池.

Figure 2-7  一个自释放池

 

autoreleasepool

iPhone OS 提示: 因为在iPhone OS 中,应用程序在一个更加内存受限的环境中运行,所以不鼓励在应用程序创建很多对象的方法或代码段中使用自释放池(比如,循环)。相反,你应该在任何可能的时候显式的释放对象。

到目前为止关于对象生命周期的讨论集中在贯穿周期的对象管理机制上。但是一个对象拥有者策略指导如何使用这些机制。这个策略可以总结如下:

·         如果你通过分配并初始化来创建( create )一个对象(比如 [[MyClass alloc] init]),你将拥有这个对象并负责释放它。这个规则同样适用于使用NSObject 简便方法(convenient methodnew

·         如果你拷贝(copy)一个对象,你将拥有这个拷贝的对象并负责释放它。

·         如果你保留( retain )一个对象,你拥有该对象部分的所有权并且当你不需要的时候释放它。

相反的,

·         如果你从其他一些对象接收一个对象,你不拥有这个对象并且不应该释放它。(这个规则有一些少数的例外,已在参考文档中显式的标注)

和任何规则集一样,有一些例外和已知问题(“gotchas”):

·         如果你通过类工厂方法创建了一个对象(比如NSMutableArray arrayWithCapacity: 方法),假设你接收的这个对象是自动释放的。你不应该自己释放这个对象而且如果你想保持其存在的话应该retain它。

·         为了避免循环引用,一个子对象永远不该retain它的父对象。(一个父对象是这个子对象的创建者或者一个以成员变量包含该这个子对象的对象。)

注意: 上面指南中的“Release”意味着发送一个release 消息或者一个autorelease 消息给一个对象。

如果你不遵循这个所有权策略,在你的应用程序中很可能会发生两件糟糕的事情。因为你没有释放创建,拷贝,或者保留的对象,你的应用程序将存在内存泄漏。或者当你给一个已从其他地方释放的对象发送消息时导致你的程序崩溃。这里还有一个警告:调试这些问题费时费力。

一个另外的可能发生在一个对象生命周期里的基本事件是归档(archiving)。归档把组成一个面向对象的程序的互相关联的对象网络-对象图-转换成一个持久格式(通常是一个文件),保存了标识和每个图中对象的关系。当程序被解归档时,它的对象图从归档中重新构建。为了参与归档(和解归档),一个对象必须能够编码(和解码)。它的成员变量使用NSCoder 类方法。 NSObject 采用NSCoding 协议来完成这个目的。更多关于对象归档的内容,请参见对象归档(“Object Archives”)。

 

英文原文链接:http://developer.apple.com/iphone/library/documentation/Cocoa/Conceptual/CocoaFundamentals/CocoaObjects/

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


我正在用TitaniumDeveloper编写一个应用程序,它允许我使用Javascript,PHP,Ruby和Python.它为API提供了一些可能需要的标准功能,但缺少的是全局事件.现在我想将全局热键分配给我的应用程序并且几乎没有任何问题.现在我只针对MAC,但无法找到任何Python或Ruby的解决方案.我找到了Coc
我的问题是当我尝试从UIWebView中调用我的AngularJS应用程序中存在的javascript函数时,该函数无法识别.当我在典型的html结构中调用该函数时,该函数被识别为预期的.示例如下:Objective-C的:-(void)viewDidLoad{[superviewDidLoad];//CODEGOESHERE_webView.d
我想获取在我的Mac上运行的所有前台应用程序的应用程序图标.我已经使用ProcessManagerAPI迭代所有应用程序.我已经确定在processMode中设置了没有modeBackgroundOnly标志的任何进程(从GetProcessInformation()中检索)是一个“前台”应用程序,并显示在任务切换器窗口中.我只需要
我是一名PHP开发人员,我使用MVC模式和面向对象的代码.我真的想为iPhone编写应用程序,但要做到这一点我需要了解Cocoa,但要做到这一点我需要了解Objective-C2.0,但要做到这一点我需要知道C,为此我需要了解编译语言(与解释相关).我应该从哪里开始?我真的需要从简单的旧“C”开始,正
OSX中的SetTimer在Windows中是否有任何等效功能?我正在使用C.所以我正在为一些软件编写一个插件,我需要定期调用一个函数.在Windows上,我只是将函数的地址传递给SetTimer(),它将以给定的间隔调用.在OSX上有一个简单的方法吗?它应该尽可能简约.我并没有在网上找到任何不花哨的东西
我不确定引擎盖下到底发生了什么,但这是我的设置,示例代码和问题:建立:>雪豹(10.6.8)>Python2.7.2(由EPD7.1-2提供)>iPython0.11(由EPD7.1-2提供)>matplotlib(由EPD7.1-2提供)示例代码:importnumpyasnpimportpylabasplx=np.random.normal(size=(1000,))pl.plot
我正在使用FoundationFramework在Objective-C(在xCode中)编写命令行工具.我必须使用Objective-C,因为我需要取消归档以前由NSKeyedArchiver归档的对象.我的问题是,我想知道我现在是否可以在我的Linux网络服务器上使用这个编译过的应用程序.我不确定是否会出现运行时问题,或者可
使用cocoapods,我们首先了解一下rvm、gem、ruby。rvm和brew一样,但是rvm是专门管理ruby的版本控制的。rvmlistknown罗列出ruby版本rvminstall版本号   可以指定更新ruby版本而gem是包管理gemsource-l查看ruby源gemsource-rhttps://xxxxxxxx移除ruby源gemsou
我有一个包含WebView的Cocoa应用程序.由于应用程序已安装客户群,我的目标是10.4SDK.(即我不能要求Leopard.)我有两个文件:index.html和data.js.在运行时,为了响应用户输入,我通常会使用应用程序中的当前数据填充data.js文件.(data.js文件由body.html上的index.html文件用于填充
如何禁用NSMenuItem?我点击后尝试禁用NSMenuItem.操作(注销)正确处理单击.我尝试通过以下两种方式将Enabled属性更改为false:partialvoidLogout(AppKit.NSMenuItemsender){sender.Enabled=false;}和partialvoidLogout(AppKit.NSMenuItemsender){LogoutI
我在想,创建一个基本上只是一个带Web视图的界面的Cocoa应用程序是否可行?做这样的事情会有一些严重的限制吗?如果它“可行”,那是否也意味着你可以为Windows应用程序做同样的事情?解决方法:当然可以创建一个只是一个Cocoa窗口的应用程序,里面有一个Web视图.这是否可以被称为“可可应
原文链接:http://www.cnblogs.com/simonshi2012/archive/2012/10/08/2715464.htmlFrom:http://www.idev101.com/code/Cocoa/Notifications.htmlNotificationsareanincrediblyusefulwaytosendmessages(anddata)betweenobjectsthatotherwi
如果不手动编写GNUmake文件,是否存在可以理解Xcode项目的任何工具,并且可以直接针对GNUstep构建它们,从而生成Linux可执行文件,从而简化(略微)保持项目在Cocoa/Mac和GNUstep/Linux下运行所需的工作?基本上,是否有适用于Linux的xcodebuild样式应用程序?几个星期前我看了pbtomake
我正在将页面加载到WebView中.该页面有这个小测试Javascript:<scripttype="text/javascript">functiontest(parametr){$('#testspan').html(parametr);}varbdu=(function(){return{secondtest:function(parametr){$('#testspan&#039
我正在尝试使用NSAppleScript从Objective-C执行一些AppleScript…但是,我正在尝试的代码是Yosemite中用于自动化的新JavaScript.它在运行时似乎没有做任何事情,但是,正常的AppleScript工作正常.[NSAppactivateIgnoringOtherApps:YES];NSAppleScript*scriptObject=[[NSApple
链接:https://pan.baidu.com/s/14_im7AmZ2Kz3qzrqIjLlAg           vjut相关文章Python与Tkinter编程ProgrammingPython(python编程)python基础教程(第二版)深入浅出PythonPython源码剖析Python核心编程(第3版)图书信息作者:Kochan,StephenG.出
我正在实现SWTJava应用程序的OSX版本的视图,并希望在我的SWT树中使用NSOutlineView提供的“源列表”选项.我通过将此代码添加到#createHandle()方法来破解我自己的Tree.class版本来实现这一点:longNSTableViewSelectionHighlightStyleSourceList=1;longhi=OS.sel_regist
我的Cocoa应用程序需要使用easy_install在用户系统上安装Python命令行工具.理想情况下,我想将一个bash文件与我的应用程序捆绑在一起然后运行.但据我所知这是不可能的,因为软件包安装在Python的“site-packages”目录中.有没有办法创建这些文件的“包”?如果没有,我应该如何运行ea
摘要: 文章工具 收藏 投票评分 发表评论 复制链接 Swing 是设计桌面应用程序的一个功能非常强大工具包,但Swing因为曾经的不足常常遭到后人的诟病.常常听到旁人议论纷纷,”Swing 运行太慢了!”,”Swing 界面太丑嘞”,甚至就是说”Swing 简直食之无味”. 从Swing被提出到现在,已是十年光景,Swing早已不是昔日一无是处的Swing了. Chris Adamson 和我写
苹果的开发:   我对于Linux/Unix的开发也是一窍不通,只知道可以用Java.不过接触了苹果过后,确实发现,世界上确实还有那么一帮人,只用苹果,不用PC的.对于苹果的开发,我也一点都不清楚,以下是师兄们整理出来的网站. http://www.chezmark.com/osx/    共享软件精选 http://www.macosxapps.com/    分类明了,更新及时的一个重要Mac