理解使用Cocoa和Objective-C进行引用计数

时间:2022-09-07 20:12:32

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 malloc and free concept, 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。我对C的malloc和free概念相当满意,但是Cocoa的引用计数方案让我有点困惑。我被告知,一旦你理解了它,它是非常优雅的,但我只是还没有结束。

How do release, retain and autorelease work and what are the conventions about their use?

如何释放、保留和自动释放工作以及它们的使用有什么约定?

(Or failing that, what did you read which helped you get it?)

(或者,你读了什么书,帮助你得到了它?)

14 个解决方案

#1


148  

Let's start with retain and release; autorelease is really just a special case once you understand the basic concepts.

让我们从保留和释放开始;一旦你理解了基本概念,autorelease就是一个特例。

In Cocoa, each object keeps track of how many times it is being referenced (specifically, the NSObject base class implements this). By calling retain on 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,您是在告诉它,您希望将它的引用计数增加1。通过调用release函数,您告诉对象您正在放开它,它的引用计数将被递减。如果在调用release之后,引用计数现在为零,那么该对象的内存将被系统释放。

The basic way this differs from malloc and free is 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 retain and 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 release on 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 autorelease is called, the current thread's NSAutoreleasePool is alerted of the call. The NSAutoreleasePool now knows that once it gets an opportunity (after the current iteration of the event loop), it can call release on the object. From our perspective as programmers, it takes care of calling release for us, so we don't have to (and in fact, we shouldn't).

现在autorelease。Autorelease被用作一种方便的(有时是必要的)方式,告诉系统在一段时间后释放这个对象。从管道的角度来看,当调用autorelease时,当前线程的NSAutoreleasePool会收到调用的警报。NSAutoreleasePool现在知道,一旦有机会(在事件循环当前迭代之后),它就可以调用对象上的release函数。从我们作为程序员的角度来看,它负责为我们调用release函数,所以我们不必这样做(事实上,我们不应该这样做)。

What's important to note is that (again, by convention) all object creation class methods 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.

需要注意的是(同样,按照约定)所有对象创建类方法都返回一个autoreleated对象。例如,在下面的示例中,变量“s”具有引用计数1,但是在事件循环完成之后,它将被销毁。

NSString* s = [NSString stringWithString:@"Hello World"];

If you want to hang onto that string, you'd need to call retain explicitly, and then explicitly release it when you're done.

如果您想要挂在那个字符串上,您需要显式地调用retain,然后在完成时显式地释放它。

Consider the following (very contrived) bit of code, and you'll see a situation where autorelease is 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 introduction to 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.
  • 《Mac OS X的Cocoa编程》(第4版),Aaron Hillegas著,这是一本写得很好的书,有很多很棒的例子。它读起来像教程。
  • 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.
  • 如果你真的在潜水,你可以去大型的书呆子农场。这是Aaron Hillegas经营的一个培训机构,他是上述书的作者。几年前我参加了那里的可可入门课程,这是一个很好的学习方式。

#2


10  

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.

如果您理解了retain/release的过程,那么有两个黄金规则对已建立的Cocoa程序员来说是显而易见的,但不幸的是,对于新手来说,很少有明确规定这一点。

  1. If a function which returns an object has alloc, create or copy in its name then the object is yours. You must call [object release] when you are finished with it. Or CFRelease(object), if it's a Core-Foundation object.

    如果一个返回对象的函数有alloc,创建或复制它的名称,那么对象就是你的。完成后必须调用[object release]。或者CFRelease(object),如果它是Core-Foundation对象。

  2. 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.

    如果它的名字里没有这些词,那么这个对象就属于其他人。如果希望在函数结束后保留对象,则必须调用[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调用是这些规则的例外,但它们很少)。

#3


8  

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垃圾收集。它真的会简化你的大部分开发——这就是为什么苹果公司会把所有的精力放在创造它上面,并让它表现得更好。

As for the memory management rules when not using GC:

关于不使用GC时的内存管理规则:

  • If you create a new object using +alloc/+allocWithZone:, +new, -copy or -mutableCopy or if you -retain an object, you are taking ownership of it and must ensure it is sent -release.
  • 如果您使用+alloc/+allocWithZone:、+new、-copy或-mutableCopy创建一个新对象,或者如果您使用-retain一个对象,那么您将获得它的所有权,并且必须确保它被发送-release。
  • If you receive an object in any other way, you are not the owner of it and should not ensure it is sent -release.
  • 如果您以任何其他方式接收一个对象,那么您不是它的所有者,并且不应该确保它被发送-release。
  • If you want to make sure an object is sent -release you can either send that yourself, or you can send the object -autorelease and the current autorelease pool will send it -release (once per received -autorelease) when the pool is drained.
  • 如果你想确保一个对象被发送出去,你可以发送你自己,或者你可以发送对象-autorelease和当前的autorelease池将发送它-释放(每个收到-autorelease)当池被耗尽。

Typically -autorelease is 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 far more common to return objects to a caller that are autoreleased than it is to return objets that the caller itself needs to release.

通常-autorelease被用作确保对象在当前事件的长度内生存的一种方式,但是在之后会被清理,因为有一个autorelease池围绕着Cocoa的事件处理。在Cocoa中,将对象返回给自压缩的调用者要比返回调用者本身需要释放的objets要常见得多。

#4


6  

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”。简单地说,当一个对象被引用(例如,存储在某处)时,它会被“保留”,这意味着它的引用计数将增加1。当一个对象不再需要时,它就被“释放”,这意味着它的引用计数减少了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引入了另一个概念,旨在使这变得更容易:自动共享。Autorelease池是在每个线程上安装的特殊对象。如果您查看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.

当对象收到发送给它的“autorelease”消息时,该对象将为当前线程查找堆栈上的任何autorelease池。它将把对象作为对象添加到列表中,以便在将来的某个时刻发送“发布”消息,这通常是在池本身被释放的时候。

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”。这是因为我们知道稍后会有一些autorelease池为我们做这件事。

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使用启用垃圾收集来构建,这样您可以完全忽略retain/release/autorelease。

#5


6  

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却没有这个功能(或者如果你想让你的应用在Mac OS X的前10.5版上运行的话)。

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模式,因此我理解,任何试图编写广泛可重用代码的人都倾向于手动管理内存。

#6


6  

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.

Apple在Cocoa内存管理编程指南中提供了一个完整的内存管理系统的描述,在该指南的最后有一个简短但准确的内存管理规则总结。

#7


6  

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

我不会增加retain/release的具体内容,除非您可能想花50美元买Hillegass的书,但是我强烈建议您在应用程序开发的早期就开始使用这些工具(甚至是您的第一本)。为此,运行->从性能工具开始。我将从泄漏开始,这只是众多可用的工具之一,但当您忘记释放时,这将有助于向您展示。你将会收到多少信息,这让人望而却步。但是,请参阅本教程,了解如何快速启动:COCOA教程:用工具修复内存泄漏

Actually trying to force leaks might be a better way of, in turn, learning how to prevent them! Good luck ;)

实际上,尝试强制泄漏可能是学习如何防止泄漏的更好方法!祝你好运,)

#8


5  

Matt Dillard wrote:

马特迪拉德写道:

return [[s autorelease] release];

生成自动返回[[s]发布);

Autorelease does not retain the object. Autorelease simply puts it in queue to be released later. You do not want to have a release statement there.

Autorelease不保留对象。Autorelease只是把它放在队列中以便稍后释放。您不希望在那里有一个发布声明。

#9


5  

My usual collection of Cocoa memory management articles:

我通常收集的可可内存管理文章:

cocoa memory management

可可内存管理

#10


4  

There's a free screencast available from the iDeveloperTV Network

iDeveloperTV网络有一个免费的视频节目

Memory Management in Objective-C

在objective - c中内存管理

#11


4  

NilObject's answer is a good start. Here's some supplemental info pertaining to manual memory management (required on the iPhone).

NilObject的答案是一个好的开始。这里有一些关于手动内存管理的补充信息(iPhone需要)。

If you personally alloc/init an object, it comes with a reference count of 1. You are responsible for cleaning up after it when it's no longer needed, either by calling [foo release] or [foo autorelease]. release cleans it up right away, whereas autorelease adds the object to the autorelease pool, which will automatically release it at a later time.

如果您亲自分配/初始化一个对象,它的引用计数为1。当它不再需要时,您负责清理它,无论是通过调用[foo发行版]还是[foo autorelease]。release立即清理它,而autorelease将对象添加到autorelease池中,该池将在稍后自动释放它。

autorelease is primarily for when you have a method that needs to return the object in question (so you can't manually release it, else you'll be returning a nil object) but you don't want to hold on to it, either.

autorelease主要用于当你有一个方法需要返回有问题的对象时(所以你不能手动释放它,否则你会返回一个nil对象),但是你也不想保留它。

If you acquire an object where you did not call alloc/init to get it -- for example:

如果你获得了一个对象,而你没有调用alloc/init来获取它——例如:

foo = [NSString stringWithString:@"hello"];

but you want to hang on to this object, you need to call [foo retain]. Otherwise, it's possible it will get autoreleased and you'll be holding on to a nil reference (as it would in the above stringWithString example). When you no longer need it, call [foo release].

但是你想要抓住这个对象,你需要调用[foo retain]。否则,它可能会自动加载,您将保持一个nil引用(就像上面stringWithString示例中的那样)。当您不再需要它时,调用[foo release]。

#12


2  

The answers above give clear restatements of what the documentation says; the problem most new people run into is the undocumented cases. For example:

上面的回答清楚地重申了文件的内容;大多数新人们遇到的问题是无证案例。例如:

  • Autorelease: docs say it will trigger a release "at some point in the future." WHEN?! Basically, you can count on the object being around until you exit your code back into the system event loop. The system MAY release the object any time after the current event cycle. (I think Matt said that, earlier.)

    Autorelease: docs说它会在将来某个时候触发一个版本。什么时候? !基本上,在将代码退出到系统事件循环之前,您可以依赖对象的存在。系统可以在当前事件周期之后的任何时间释放该对象。(我想马特早些时候说过。)

  • Static strings: NSString *foo = @"bar"; -- do you have to retain or release that? No. How about

    静态字符串:NSString *foo = @“bar”;——你必须保留或释放它吗?不。如何

    -(void)getBar {
        return @"bar";
    }
    

    ...

    NSString *foo = [self getBar]; // still no need to retain or release
    
  • The Creation Rule: If you created it, you own it, and are expected to release it.

    创建规则:如果您创建了它,那么您拥有它,并期望发布它。

In general, the way new Cocoa programmers get messed up is by not understanding which routines return an object with a retainCount > 0.

通常,新的Cocoa程序员搞砸的方法是不理解哪些例程返回带有retainCount >的对象。

Here is a snippet from Very Simple Rules For Memory Management In Cocoa:

以下是Cocoa中非常简单的内存管理规则的一个片段:

Retention Count rules

保留计数规则

  • Within a given block, the use of -copy, -alloc and -retain should equal the use of -release and -autorelease.
  • 在给定的块中,使用-copy、-alloc和-retain应该等于使用-release和-autorelease。
  • Objects created using convenience constructors (e.g. NSString's stringWithString) are considered autoreleased.
  • 使用方便构造函数创建的对象(例如NSString的stringWithString)被认为是自动生成的。
  • Implement a -dealloc method to release the instancevariables you own
  • 实现一个-dealloc方法来释放您所拥有的instancevariables

The 1st bullet says: if you called alloc (or new fooCopy), you need to call release on that object.

第一颗子弹说:如果你调用alloc(或新fooCopy),你需要调用那个对象的release。

The 2nd bullet says: if you use a convenience constructor and you need the object to hang around (as with an image to be drawn later), you need to retain (and then later release) it.

第二颗子弹说:如果你使用一个方便的构造函数,并且你需要这个对象挂在那里(就像后面要画的图像一样),你需要保留它(然后再发布)。

The 3rd should be self-explanatory.

第三点应该不言自明。

#13


1  

Lots of good information on cocoadev too:

关于cocoadev也有很多好的信息:

#14


0  

As several people mentioned already, Apple's Intro to Memory Management is by far the best place to start.

正如一些人已经提到的,到目前为止,苹果的内存管理入门是最好的起点。

One useful link I haven't seen mentioned yet is Practical Memory Management. You'll find it in the middle of Apple's docs if you read through them, but it's worth direct linking. It's a brilliant executive summary of the memory management rules with examples and common mistakes (basically what other answers here are trying to explain, but not as well).

我还没有提到的一个有用的链接是实用内存管理。如果你通读一下苹果的文档,你会发现它就在文档的中间,但它值得直接链接。这是一个出色的内存管理规则的执行总结,包含了示例和常见错误(这里的其他答案基本上是要解释的,但也不是同样的)。

#1


148  

Let's start with retain and release; autorelease is really just a special case once you understand the basic concepts.

让我们从保留和释放开始;一旦你理解了基本概念,autorelease就是一个特例。

In Cocoa, each object keeps track of how many times it is being referenced (specifically, the NSObject base class implements this). By calling retain on 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,您是在告诉它,您希望将它的引用计数增加1。通过调用release函数,您告诉对象您正在放开它,它的引用计数将被递减。如果在调用release之后,引用计数现在为零,那么该对象的内存将被系统释放。

The basic way this differs from malloc and free is 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 retain and 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 release on 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 autorelease is called, the current thread's NSAutoreleasePool is alerted of the call. The NSAutoreleasePool now knows that once it gets an opportunity (after the current iteration of the event loop), it can call release on the object. From our perspective as programmers, it takes care of calling release for us, so we don't have to (and in fact, we shouldn't).

现在autorelease。Autorelease被用作一种方便的(有时是必要的)方式,告诉系统在一段时间后释放这个对象。从管道的角度来看,当调用autorelease时,当前线程的NSAutoreleasePool会收到调用的警报。NSAutoreleasePool现在知道,一旦有机会(在事件循环当前迭代之后),它就可以调用对象上的release函数。从我们作为程序员的角度来看,它负责为我们调用release函数,所以我们不必这样做(事实上,我们不应该这样做)。

What's important to note is that (again, by convention) all object creation class methods 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.

需要注意的是(同样,按照约定)所有对象创建类方法都返回一个autoreleated对象。例如,在下面的示例中,变量“s”具有引用计数1,但是在事件循环完成之后,它将被销毁。

NSString* s = [NSString stringWithString:@"Hello World"];

If you want to hang onto that string, you'd need to call retain explicitly, and then explicitly release it when you're done.

如果您想要挂在那个字符串上,您需要显式地调用retain,然后在完成时显式地释放它。

Consider the following (very contrived) bit of code, and you'll see a situation where autorelease is 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 introduction to 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.
  • 《Mac OS X的Cocoa编程》(第4版),Aaron Hillegas著,这是一本写得很好的书,有很多很棒的例子。它读起来像教程。
  • 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.
  • 如果你真的在潜水,你可以去大型的书呆子农场。这是Aaron Hillegas经营的一个培训机构,他是上述书的作者。几年前我参加了那里的可可入门课程,这是一个很好的学习方式。

#2


10  

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.

如果您理解了retain/release的过程,那么有两个黄金规则对已建立的Cocoa程序员来说是显而易见的,但不幸的是,对于新手来说,很少有明确规定这一点。

  1. If a function which returns an object has alloc, create or copy in its name then the object is yours. You must call [object release] when you are finished with it. Or CFRelease(object), if it's a Core-Foundation object.

    如果一个返回对象的函数有alloc,创建或复制它的名称,那么对象就是你的。完成后必须调用[object release]。或者CFRelease(object),如果它是Core-Foundation对象。

  2. 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.

    如果它的名字里没有这些词,那么这个对象就属于其他人。如果希望在函数结束后保留对象,则必须调用[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调用是这些规则的例外,但它们很少)。

#3


8  

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垃圾收集。它真的会简化你的大部分开发——这就是为什么苹果公司会把所有的精力放在创造它上面,并让它表现得更好。

As for the memory management rules when not using GC:

关于不使用GC时的内存管理规则:

  • If you create a new object using +alloc/+allocWithZone:, +new, -copy or -mutableCopy or if you -retain an object, you are taking ownership of it and must ensure it is sent -release.
  • 如果您使用+alloc/+allocWithZone:、+new、-copy或-mutableCopy创建一个新对象,或者如果您使用-retain一个对象,那么您将获得它的所有权,并且必须确保它被发送-release。
  • If you receive an object in any other way, you are not the owner of it and should not ensure it is sent -release.
  • 如果您以任何其他方式接收一个对象,那么您不是它的所有者,并且不应该确保它被发送-release。
  • If you want to make sure an object is sent -release you can either send that yourself, or you can send the object -autorelease and the current autorelease pool will send it -release (once per received -autorelease) when the pool is drained.
  • 如果你想确保一个对象被发送出去,你可以发送你自己,或者你可以发送对象-autorelease和当前的autorelease池将发送它-释放(每个收到-autorelease)当池被耗尽。

Typically -autorelease is 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 far more common to return objects to a caller that are autoreleased than it is to return objets that the caller itself needs to release.

通常-autorelease被用作确保对象在当前事件的长度内生存的一种方式,但是在之后会被清理,因为有一个autorelease池围绕着Cocoa的事件处理。在Cocoa中,将对象返回给自压缩的调用者要比返回调用者本身需要释放的objets要常见得多。

#4


6  

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”。简单地说,当一个对象被引用(例如,存储在某处)时,它会被“保留”,这意味着它的引用计数将增加1。当一个对象不再需要时,它就被“释放”,这意味着它的引用计数减少了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引入了另一个概念,旨在使这变得更容易:自动共享。Autorelease池是在每个线程上安装的特殊对象。如果您查看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.

当对象收到发送给它的“autorelease”消息时,该对象将为当前线程查找堆栈上的任何autorelease池。它将把对象作为对象添加到列表中,以便在将来的某个时刻发送“发布”消息,这通常是在池本身被释放的时候。

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”。这是因为我们知道稍后会有一些autorelease池为我们做这件事。

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使用启用垃圾收集来构建,这样您可以完全忽略retain/release/autorelease。

#5


6  

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却没有这个功能(或者如果你想让你的应用在Mac OS X的前10.5版上运行的话)。

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模式,因此我理解,任何试图编写广泛可重用代码的人都倾向于手动管理内存。

#6


6  

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.

Apple在Cocoa内存管理编程指南中提供了一个完整的内存管理系统的描述,在该指南的最后有一个简短但准确的内存管理规则总结。

#7


6  

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

我不会增加retain/release的具体内容,除非您可能想花50美元买Hillegass的书,但是我强烈建议您在应用程序开发的早期就开始使用这些工具(甚至是您的第一本)。为此,运行->从性能工具开始。我将从泄漏开始,这只是众多可用的工具之一,但当您忘记释放时,这将有助于向您展示。你将会收到多少信息,这让人望而却步。但是,请参阅本教程,了解如何快速启动:COCOA教程:用工具修复内存泄漏

Actually trying to force leaks might be a better way of, in turn, learning how to prevent them! Good luck ;)

实际上,尝试强制泄漏可能是学习如何防止泄漏的更好方法!祝你好运,)

#8


5  

Matt Dillard wrote:

马特迪拉德写道:

return [[s autorelease] release];

生成自动返回[[s]发布);

Autorelease does not retain the object. Autorelease simply puts it in queue to be released later. You do not want to have a release statement there.

Autorelease不保留对象。Autorelease只是把它放在队列中以便稍后释放。您不希望在那里有一个发布声明。

#9


5  

My usual collection of Cocoa memory management articles:

我通常收集的可可内存管理文章:

cocoa memory management

可可内存管理

#10


4  

There's a free screencast available from the iDeveloperTV Network

iDeveloperTV网络有一个免费的视频节目

Memory Management in Objective-C

在objective - c中内存管理

#11


4  

NilObject's answer is a good start. Here's some supplemental info pertaining to manual memory management (required on the iPhone).

NilObject的答案是一个好的开始。这里有一些关于手动内存管理的补充信息(iPhone需要)。

If you personally alloc/init an object, it comes with a reference count of 1. You are responsible for cleaning up after it when it's no longer needed, either by calling [foo release] or [foo autorelease]. release cleans it up right away, whereas autorelease adds the object to the autorelease pool, which will automatically release it at a later time.

如果您亲自分配/初始化一个对象,它的引用计数为1。当它不再需要时,您负责清理它,无论是通过调用[foo发行版]还是[foo autorelease]。release立即清理它,而autorelease将对象添加到autorelease池中,该池将在稍后自动释放它。

autorelease is primarily for when you have a method that needs to return the object in question (so you can't manually release it, else you'll be returning a nil object) but you don't want to hold on to it, either.

autorelease主要用于当你有一个方法需要返回有问题的对象时(所以你不能手动释放它,否则你会返回一个nil对象),但是你也不想保留它。

If you acquire an object where you did not call alloc/init to get it -- for example:

如果你获得了一个对象,而你没有调用alloc/init来获取它——例如:

foo = [NSString stringWithString:@"hello"];

but you want to hang on to this object, you need to call [foo retain]. Otherwise, it's possible it will get autoreleased and you'll be holding on to a nil reference (as it would in the above stringWithString example). When you no longer need it, call [foo release].

但是你想要抓住这个对象,你需要调用[foo retain]。否则,它可能会自动加载,您将保持一个nil引用(就像上面stringWithString示例中的那样)。当您不再需要它时,调用[foo release]。

#12


2  

The answers above give clear restatements of what the documentation says; the problem most new people run into is the undocumented cases. For example:

上面的回答清楚地重申了文件的内容;大多数新人们遇到的问题是无证案例。例如:

  • Autorelease: docs say it will trigger a release "at some point in the future." WHEN?! Basically, you can count on the object being around until you exit your code back into the system event loop. The system MAY release the object any time after the current event cycle. (I think Matt said that, earlier.)

    Autorelease: docs说它会在将来某个时候触发一个版本。什么时候? !基本上,在将代码退出到系统事件循环之前,您可以依赖对象的存在。系统可以在当前事件周期之后的任何时间释放该对象。(我想马特早些时候说过。)

  • Static strings: NSString *foo = @"bar"; -- do you have to retain or release that? No. How about

    静态字符串:NSString *foo = @“bar”;——你必须保留或释放它吗?不。如何

    -(void)getBar {
        return @"bar";
    }
    

    ...

    NSString *foo = [self getBar]; // still no need to retain or release
    
  • The Creation Rule: If you created it, you own it, and are expected to release it.

    创建规则:如果您创建了它,那么您拥有它,并期望发布它。

In general, the way new Cocoa programmers get messed up is by not understanding which routines return an object with a retainCount > 0.

通常,新的Cocoa程序员搞砸的方法是不理解哪些例程返回带有retainCount >的对象。

Here is a snippet from Very Simple Rules For Memory Management In Cocoa:

以下是Cocoa中非常简单的内存管理规则的一个片段:

Retention Count rules

保留计数规则

  • Within a given block, the use of -copy, -alloc and -retain should equal the use of -release and -autorelease.
  • 在给定的块中,使用-copy、-alloc和-retain应该等于使用-release和-autorelease。
  • Objects created using convenience constructors (e.g. NSString's stringWithString) are considered autoreleased.
  • 使用方便构造函数创建的对象(例如NSString的stringWithString)被认为是自动生成的。
  • Implement a -dealloc method to release the instancevariables you own
  • 实现一个-dealloc方法来释放您所拥有的instancevariables

The 1st bullet says: if you called alloc (or new fooCopy), you need to call release on that object.

第一颗子弹说:如果你调用alloc(或新fooCopy),你需要调用那个对象的release。

The 2nd bullet says: if you use a convenience constructor and you need the object to hang around (as with an image to be drawn later), you need to retain (and then later release) it.

第二颗子弹说:如果你使用一个方便的构造函数,并且你需要这个对象挂在那里(就像后面要画的图像一样),你需要保留它(然后再发布)。

The 3rd should be self-explanatory.

第三点应该不言自明。

#13


1  

Lots of good information on cocoadev too:

关于cocoadev也有很多好的信息:

#14


0  

As several people mentioned already, Apple's Intro to Memory Management is by far the best place to start.

正如一些人已经提到的,到目前为止,苹果的内存管理入门是最好的起点。

One useful link I haven't seen mentioned yet is Practical Memory Management. You'll find it in the middle of Apple's docs if you read through them, but it's worth direct linking. It's a brilliant executive summary of the memory management rules with examples and common mistakes (basically what other answers here are trying to explain, but not as well).

我还没有提到的一个有用的链接是实用内存管理。如果你通读一下苹果的文档,你会发现它就在文档的中间,但它值得直接链接。这是一个出色的内存管理规则的执行总结,包含了示例和常见错误(这里的其他答案基本上是要解释的,但也不是同样的)。