使用 Cocoa 和 Objective-C 理解引用计数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6578/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Understanding reference counting with Cocoa and Objective-C
提问by Matt Sheppard
I'm just beginning to have a look at Objective-C and Cocoa with a view to playing with the iPhone SDK. I'm reasonably comfortable with C's mallocand freeconcept, but Cocoa's references counting scheme has me rather confused. I'm told it's very elegant once you understand it, but I'm just not over the hump yet.
我刚刚开始研究 Objective-C 和 Cocoa,以期使用 iPhone SDK。我对 Cmalloc和free概念相当满意,但是 Cocoa 的引用计数方案让我很困惑。有人告诉我,一旦你理解它,它就会非常优雅,但我还没有克服困难。
How do release, retainand autoreleasework and what are the conventions about their use?
怎么办release,retain和autorelease工作有什么关于他们使用的约定?
(Or failing that, what did you read which helped you get it?)
(或者失败了,你读了什么帮助你得到它?)
回答by Matt Dillard
Let's start with retainand release; autoreleaseis really just a special case once you understand the basic concepts.
让我们从retain和开始release;autorelease一旦你理解了基本概念,这真的只是一个特例。
In Cocoa, each object keeps track of how many times it is being referenced (specifically, the NSObjectbase class implements this). By calling retainon an object, you are telling it that you want to up its reference count by one. By calling release, you tell the object you are letting go of it, and its reference count is decremented. If, after calling release, the reference count is now zero, then that object's memory is freed by the system.
在 Cocoa 中,每个对象都会跟踪它被引用的次数(具体来说,NSObject基类实现了这一点)。通过调用retain一个对象,你告诉它你想将它的引用计数加一。通过调用release,您告诉对象您要释放它,并且它的引用计数减少。如果在调用 之后release,引用计数现在为零,则系统会释放该对象的内存。
The basic way this differs from mallocand freeis that any given object doesn't need to worry about other parts of the system crashing because you've freed memory they were using. Assuming everyone is playing along and retaining/releasing according to the rules, when one piece of code retains and then releases the object, any other piece of code also referencing the object will be unaffected.
基本方式这不同于malloc并free为任何给定的对象并不需要对系统崩溃,因为你他们使用释放的内存的其他部分忧虑。假设每个人都按照规则在玩,保留/释放,当一段代码保留然后释放对象时,任何其他引用该对象的代码都不会受到影响。
What can sometimes be confusing is knowing the circumstances under which you should call retainand release. My general rule of thumb is that if I want to hang on to an object for some length of time (if it's a member variable in a class, for instance), then I need to make sure the object's reference count knows about me. As described above, an object's reference count is incremented by calling retain. By convention, it is also incremented (set to 1, really) when the object is created with an "init" method. In either of these cases, it is my responsibility to call releaseon the object when I'm done with it. If I don't, there will be a memory leak.
有时令人困惑的是知道在什么情况下应该调用retain和release。我的一般经验法则是,如果我想保留某个对象一段时间(例如,如果它是类中的成员变量),那么我需要确保该对象的引用计数知道我。如上所述,对象的引用计数通过调用retain. 按照惯例,当使用“init”方法创建对象时,它也会递增(实际上设置为 1)。在这两种情况中的任何一种情况下,我都有责任在完成后调用release该对象。如果我不这样做,就会出现内存泄漏。
Example of object creation:
对象创建示例:
NSString* s = [[NSString alloc] init]; // Ref count is 1
[s retain]; // Ref count is 2 - silly
// to do this after init
[s release]; // Ref count is back to 1
[s release]; // Ref count is 0, object is freed
Now for autorelease. Autorelease is used as a convenient (and sometimes necessary) way to tell the system to free this object up after a little while. From a plumbing perspective, when autoreleaseis called, the current thread's NSAutoreleasePoolis alerted of the call. The NSAutoreleasePoolnow knows that once it gets an opportunity (after the current iteration of the event loop), it can call releaseon the object. From our perspective as programmers, it takes care of calling releasefor us, so we don't have to (and in fact, we shouldn't).
现在对于autorelease. 自动释放被用作一种方便(有时是必要的)方式来告诉系统在一段时间后释放这个对象。从管道的角度来看,当autorelease被调用时,当前线程NSAutoreleasePool会收到该调用的警报。在NSAutoreleasePool现在知道,一旦它得到一个机会(事件循环的当前迭代之后),它可以调用release的对象。从我们程序员的角度来看,它负责调用release我们,所以我们不必(事实上,我们不应该)。
What's important to note is that (again, by convention) all object creation classmethods return an autoreleased object. For example, in the following example, the variable "s" has a reference count of 1, but after the event loop completes, it will be destroyed.
需要注意的重要一点是(再次按照惯例)所有对象创建类方法都返回一个自动释放的对象。例如,在下面的示例中,变量“s”的引用计数为 1,但在事件循环完成后,它将被销毁。
NSString* s = [NSString stringWithString:@"Hello World"];
If you want to hang onto that string, you'd need to call retainexplicitly, and then explicitly releaseit when you're done.
如果您想保留该字符串,则需要retain显式调用,然后release在完成后显式调用它。
Consider the following (very contrived) bit of code, and you'll see a situation where autoreleaseis required:
考虑以下(非常人为的)代码,您将看到需要的情况autorelease:
- (NSString*)createHelloWorldString
{
NSString* s = [[NSString alloc] initWithString:@"Hello World"];
// Now what? We want to return s, but we've upped its reference count.
// The caller shouldn't be responsible for releasing it, since we're the
// ones that created it. If we call release, however, the reference
// count will hit zero and bad memory will be returned to the caller.
// The answer is to call autorelease before returning the string. By
// explicitly calling autorelease, we pass the responsibility for
// releasing the string on to the thread's NSAutoreleasePool, which will
// happen at some later time. The consequence is that the returned string
// will still be valid for the caller of this function.
return [s autorelease];
}
I realize all of this is a bit confusing - at some point, though, it will click. Here are a few references to get you going:
我意识到所有这些都有些令人困惑——不过,在某些时候,它会点击。以下是一些参考资料,可助您一臂之力:
- Apple's introductionto memory management.
- Cocoa Programming for Mac OS X (4th Edition), by Aaron Hillegas - a very well written book with lots of great examples. It reads like a tutorial.
- If you're truly diving in, you could head to Big Nerd Ranch. This is a training facility run by Aaron Hillegas - the author of the book mentioned above. I attended the Intro to Cocoa course there several years ago, and it was a great way to learn.
- Apple对内存管理的介绍。
- Cocoa Programming for Mac OS X(第 4 版),作者 Aaron Hillegas - 一本写得很好的书,里面有很多很好的例子。它读起来像一个教程。
- 如果你真的想潜入,你可以去大书呆子牧场。这是一个由 Aaron Hillegas 经营的培训机构,他是上述书籍的作者。几年前我在那里参加了可可入门课程,这是一种很好的学习方式。
回答by Andrew Grant
If you understand the process of retain/release then there are two golden rules that are "duh" obvious to established Cocoa programmers, but unfortunately are rarely spelled out this clearly for newcomers.
如果您了解保留/释放的过程,那么有两个黄金法则对成熟的 Cocoa 程序员来说是显而易见的,但不幸的是,很少为新手清楚地阐明这一点。
If a function which returns an object has
alloc,createorcopyin its name then the object is yours. You must call[object release]when you are finished with it. OrCFRelease(object), if it's a Core-Foundation object.If it does NOT have one of these words in its name then the object belongs to someone else. You must call
[object retain]if you wish to keep the object after the end of your function.
如果返回对象的函数具有
alloc,create或copy在其名称中,则该对象是您的。[object release]完成后必须打电话。或者CFRelease(object),如果它是一个 Core-Foundation 对象。如果它的名称中没有这些词之一,则该对象属于其他人。
[object retain]如果您希望在函数结束后保留对象,则必须调用。
You would be well served to also follow this convention in functions you create yourself.
在您自己创建的函数中也遵循此约定会很好。
(Nitpickers: Yes, there are unfortunately a few API calls that are exceptions to these rules but they are rare).
(挑剔者:是的,不幸的是,有一些 API 调用是这些规则的例外,但它们很少见)。
回答by Chris Hanson
If you're writing code for the desktop and you can target Mac OS X 10.5, you should at least look into using Objective-C garbage collection. It really will simplify most of your development — that's why Apple put all the effort into creating it in the first place, and making it perform well.
如果您正在为桌面编写代码并且可以面向 Mac OS X 10.5,那么您至少应该考虑使用 Objective-C 垃圾收集。它确实会简化您的大部分开发工作——这就是为什么 Apple 一开始就全力打造它,并使其表现良好。
As for the memory management rules when not using GC:
至于不使用GC时的内存管理规则:
- If you create a new object using
+alloc/+allocWithZone:,+new,-copyor-mutableCopyor if you-retainan object, you are taking ownership of it and must ensure it is sent-release. - If you receive an object in any other way, you are notthe owner of it and should notensure it is sent
-release. - If you want to make sure an object is sent
-releaseyou can either send that yourself, or you can send the object-autoreleaseand the current autorelease poolwill send it-release(once per received-autorelease) when the pool is drained.
- 如果您使用创建一个新的对象
+alloc/+allocWithZone:,+new,-copy或者-mutableCopy,或者如果你-retain的目标,你正在服用它的所有权,必须确保它被发送-release。 - 如果您收到任何其他方式的对象,你是不是它的主人,应该不保证其发送
-release。 - 如果您想确保发送一个对象,
-release您可以自己发送该对象-autorelease,也可以发送该对象,当前自动释放池将在池耗尽时发送它-release(每次收到一次-autorelease)。
Typically -autoreleaseis used as a way of ensuring that objects live for the length of the current event, but are cleaned up afterwards, as there is an autorelease pool that surrounds Cocoa's event processing. In Cocoa, it is farmore common to return objects to a caller that are autoreleased than it is to return objets that the caller itself needs to release.
通常-autorelease用作确保对象在当前事件期间存活的一种方式,但之后会被清理,因为 Cocoa 的事件处理周围有一个自动释放池。在可可,它是远远更常见的对象返回到被自动释放比它返回OBJETS调用者本身需要释放调用者。
回答by mmalc
As ever, when people start trying to re-word the reference material they almost invariably get something wrong or provide an incomplete description.
与以往一样,当人们开始尝试重新表述参考资料时,他们几乎总是会出错或提供不完整的描述。
Apple provides a complete description of Cocoa's memory management system in Memory Management Programming Guide for Cocoa, at the end of which there is a brief but accurate summary of the Memory Management Rules.
苹果在 Cocoa 的内存管理编程指南中对Cocoa 的内存管理系统进行了完整的描述,最后有对内存管理规则的简要但准确的总结。
回答by Rob
I'll not add to the specific of retain/release other than you might want to think about dropping $50 and getting the Hillegass book, but I would strongly suggest getting into using the Instruments tools very early in the development of your application (even your first one!). To do so, Run->Start with performance tools. I'd start with Leaks which is just one of many of the instruments available but will help to show you when you've forgot to release. It's quit daunting how much information you'll be presented with. But check out this tutorial to get up and going fast:
COCOA TUTORIAL: FIXING MEMORY LEAKS WITH INSTRUMENTS
除了您可能想考虑花 50 美元购买 Hillegass 书籍之外,我不会添加保留/发布的具体内容,但我强烈建议您在应用程序开发的早期就开始使用 Instruments 工具(甚至您的第一!)。为此,请运行->从性能工具开始。我将从 Leaks 开始,它只是众多可用工具中的一种,但会在您忘记发布时向您展示。您将看到多少信息并不令人生畏。但是请查看本教程以快速入门:
COCOA 教程:使用仪器修复内存泄漏
Actually trying to forceleaks might be a better way of, in turn, learning how to prevent them! Good luck ;)
实际上,尝试强制泄漏可能是学习如何防止泄漏的更好方法!祝你好运 ;)
回答by NilObject
Objective-C uses Reference Counting, which means each Object has a reference count. When an object is created, it has a reference count of "1". Simply speaking, when an object is referred to (ie, stored somewhere), it gets "retained" which means its reference count is increased by one. When an object is no longer needed, it is "released" which means its reference count is decreased by one.
Objective-C 使用引用计数,这意味着每个对象都有一个引用计数。创建对象时,它的引用计数为“1”。简单地说,当一个对象被引用(即存储在某处)时,它会被“保留”,这意味着它的引用计数增加一。当一个对象不再需要时,它被“释放”,这意味着它的引用计数减一。
When an object's reference count is 0, the object is freed. This is basic reference counting.
当一个对象的引用计数为 0 时,该对象被释放。这是基本的引用计数。
For some languages, references are automatically increased and decreased, but objective-c is not one of those languages. Thus the programmer is responsible for retaining and releasing.
对于某些语言,引用会自动增加和减少,但 Objective-c 不是这些语言之一。因此程序员负责保留和释放。
A typical way to write a method is:
编写方法的典型方法是:
id myVar = [someObject someMessage];
.... do something ....;
[myVar release];
return someValue;
The problem of needing to remember to release any acquired resources inside of code is both tedious and error-prone. Objective-C introduces another concept aimed at making this much easier: Autorelease Pools. Autorelease pools are special objects that are installed on each thread. They are a fairly simple class, if you look up NSAutoreleasePool.
需要记住在代码中释放任何获得的资源的问题既乏味又容易出错。Objective-C 引入了另一个旨在使这变得更容易的概念:自动释放池。自动释放池是安装在每个线程上的特殊对象。如果您查找 NSAutoreleasePool,它们是一个相当简单的类。
When an object gets an "autorelease" message sent to it, the object will look for any autorelease pools sitting on the stack for this current thread. It will add the object to the list as an object to send a "release" message to at some point in the future, which is generally when the pool itself is released.
当对象收到发送给它的“自动释放”消息时,该对象将查找位于当前线程堆栈上的任何自动释放池。它会将对象作为对象添加到列表中,以便在将来的某个时刻向其发送“释放”消息,这通常是在池本身被释放时。
Taking the code above, you can rewrite it to be shorter and easier to read by saying:
使用上面的代码,您可以通过以下方式将其重写为更短且更易于阅读:
id myVar = [[someObject someMessage] autorelease];
... do something ...;
return someValue;
Because the object is autoreleased, we no longer need to explicitly call "release" on it. This is because we know some autorelease pool will do it for us later.
因为该对象是自动释放的,所以我们不再需要对其显式调用“release”。这是因为我们知道一些自动释放池稍后会为我们做这件事。
Hopefully this helps. The Wikipedia article is pretty good about reference counting. More information about autorelease pools can be found here. Also note that if you are building for Mac OS X 10.5 and later, you can tell Xcode to build with garbage collection enabled, allowing you to completely ignore retain/release/autorelease.
希望这会有所帮助。维基百科文章关于引用计数非常好。可以在此处找到有关自动释放池的更多信息。另请注意,如果您正在为 Mac OS X 10.5 及更高版本构建,您可以告诉 Xcode 在启用垃圾收集的情况下构建,从而允许您完全忽略保留/释放/自动释放。
回答by Matt Sheppard
Joshua (#6591) - The Garbage collection stuff in Mac OS X 10.5 seems pretty cool, but isn't available for the iPhone (or if you want your app to run on pre-10.5 versions of Mac OS X).
Joshua (#6591) - Mac OS X 10.5 中的垃圾收集东西看起来很酷,但不适用于 iPhone(或者如果您希望您的应用程序在 10.5 之前的 Mac OS X 版本上运行)。
Also, if you're writing a library or something that might be reused, using the GC mode locks anyone using the code into also using the GC mode, so as I understand it, anyone trying to write widely reusable code tends to go for managing memory manually.
此外,如果您正在编写一个库或可能被重用的东西,使用 GC 模式会将使用代码的任何人锁定为也使用 GC 模式,所以据我所知,任何试图编写广泛可重用的代码的人都倾向于去管理手动记忆。
回答by NilObject
return [[s autorelease] release];
return [[s autorelease] release];
Autorelease does notretain the object. Autorelease simply puts it in queue to be released later. You do not want to have a release statement there.
自动释放并没有挽留的对象。Autorelease 只是将它放在队列中以便稍后发布。您不希望在那里有发布声明。
回答by NilObject
My usual collection of Cocoa memory management articles:
我平时收集的 Cocoa 内存管理文章:
回答by Abizern
There's a free screencast available from the iDeveloperTV Network
iDeveloperTV 网络提供免费截屏视频

