123

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.

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?)

4

14 に答える 14

149

retainrelease;から始めましょう。autorelease基本的な概念を理解すれば、実際には特殊なケースにすぎません。

Cocoa では、各オブジェクトが参照された回数を追跡します (具体的には、NSObject基本クラスがこれを実装します)。オブジェクトを呼び出すことretainで、参照カウントを 1 つ増やしたいことをオブジェクトに伝えます。を呼び出すことreleaseで、オブジェクトを手放すことを伝え、その参照カウントを減らします。を呼び出した後release、参照カウントがゼロになった場合、そのオブジェクトのメモリはシステムによって解放されます。

これが異なる基本的な方法mallocfree、オブジェクトが使用していたメモリを解放したため、特定のオブジェクトがシステムの他の部分がクラッシュすることを心配する必要がないことです。誰もがルールに従ってプレイし、保持/解放していると仮定すると、1 つのコードがオブジェクトを保持してから解放しても、そのオブジェクトを参照している他のコードは影響を受けません。

retain混乱を招くことがあるのは、とを呼び出す必要がある状況を知ることですrelease。私の一般的な経験則は、あるオブジェクトをしばらく保持したい場合 (たとえば、それがクラスのメンバー変数である場合)、オブジェクトの参照カウントが私について知っていることを確認する必要があるということです。前述のように、オブジェクトの参照カウントは を呼び出すことでインクリメントされますretain。慣例により、オブジェクトが「init」メソッドで作成されたときにもインクリメントされます (実際には 1 に設定されます)。どちらの場合でもrelease、オブジェクトを使い終わったときにオブジェクトを呼び出すのは私の責任です。そうしないと、メモリリークが発生します。

オブジェクト作成の例:

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

今すぐautorelease。Autorelease は、しばらくしてからこのオブジェクトを解放するようにシステムに指示する便利な (そして場合によっては必要な) 方法として使用されます。配管の観点からは、autoreleaseが呼び出されると、現在のスレッドNSAutoreleasePoolに呼び出しが通知されます。は、(イベント ループのNSAutoreleasePool現在の繰り返しの後) 機会が得られるとrelease、オブジェクトを呼び出すことができることを認識しています。プログラマーとしての私たちの観点からは、呼び出しreleaseを処理してくれるので、呼び出す必要はありません (実際、そうすべきではありません)。

注意すべき重要な点は、(繰り返しますが、慣例により) すべてのオブジェクト作成クラスメソッドは、自動解放されたオブジェクトを返すということです。たとえば、次の例では、変数 "s" は参照カウントが 1 ですが、イベント ループが完了すると破棄されます。

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

その文字列に固執したい場合は、明示的に呼び出し、完了したらretain明示的に呼び出す必要がありreleaseます。

次の (非常に不自然な) コードのビットを検討すると、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];
}

私はこれがすべて少し混乱していることに気付きました - しかし、ある時点で、それはクリックします. ここにあなたが始めるためのいくつかの参考文献があります:

于 2008-08-09T04:40:49.250 に答える
10

保持/解放のプロセスを理解している場合、確立されたCocoaプログラマーにとって「当たり前」の2つの黄金のルールがありますが、残念ながら、これが初心者にとって明確に説明されていることはめったにありません。

  1. オブジェクトを返す関数にalloccreateまたはcopyその名前が含まれている場合、そのオブジェクトはあなたのものです。[object release]使い終わったら電話する必要があります。またはCFRelease(object)、Core-Foundationオブジェクトの場合。

  2. 名前にこれらの単語のいずれかが含まれていない場合、オブジェクトは他の誰かに属しています。[object retain]関数の終了後もオブジェクトを保持したい場合は、を呼び出す必要があります。

自分で作成した関数でも、この規則に従うことができます。

(Nitpickers:はい、残念ながら、これらのルールの例外であるAPI呼び出しがいくつかありますが、それらはまれです)。

于 2008-08-11T18:42:33.793 に答える
8

デスクトップ用のコードを書いていて、Mac OS X 10.5 をターゲットにできる場合は、少なくとも Objective-C ガベージ コレクションの使用を検討する必要があります。これにより、開発の大部分が本当に簡素化されます。そのため、Apple は最初から開発に全力を注ぎ、優れたパフォーマンスを発揮できるようにしました。

GC を使用しない場合のメモリ管理規則については、次のとおりです。

  • を使用して新しいオブジェクトを作成する場合、+alloc/+allocWithZone:またはオブジェクトの場合は+new、その所有権を取得することになり、送信されていることを確認する必要があります。-copy-mutableCopy-retain-release
  • 他の方法でオブジェクトを受け取った場合、あなたはそのオブジェクトの所有者ではないため、オブジェクトが送信されたことを保証するべきではありませ-release
  • オブジェクトが送信されたことを確認したい場合は-release、それを自分で送信するか、オブジェクトを送信して、プールが空になったとき-autoreleaseに現在の自動解放プール-releaseがそれを(受信ごとに 1 回)送信し-autoreleaseます。

Cocoa のイベント処理を囲む自動解放プールがあるため、通常-autorelease、オブジェクトが現在のイベントの間存続することを保証する方法として使用されますが、後でクリーンアップされます。Cocoa では、呼び出し元自体が解放する必要があるオブジェクトを返すよりも、自動解放されたオブジェクトを呼び出し元に返す方がはるかに一般的です。

于 2008-08-09T22:27:12.860 に答える
6

相変わらず、人々が参考資料を言い換えようとすると、ほとんどの場合、何か間違ったことをしたり、不完全な説明を提供したりします。

Appleは、Cocoaのメモリ管理プログラミングガイドでCocoaのメモリ管理システムの完全な説明を提供しています。最後に、メモリ管理ルールの簡潔で正確な要約があります。

于 2008-10-20T00:42:12.933 に答える
6

Objective-C は参照カウントを使用します。つまり、各オブジェクトには参照カウントがあります。オブジェクトが作成されると、その参照カウントは「1」になります。簡単に言えば、オブジェクトが参照される (つまり、どこかに保存される) と、そのオブジェクトは「保持」されます。つまり、参照カウントが 1 つ増えます。オブジェクトが不要になると、そのオブジェクトは「解放」されます。これは、参照カウントが 1 つ減ることを意味します。

オブジェクトの参照カウントが 0 の場合、オブジェクトは解放されます。これは基本的な参照カウントです。

一部の言語では、参照が自動的に増減されますが、objective-c はそれらの言語の 1 つではありません。したがって、プログラマーは保持と解放を担当します。

メソッドを記述する一般的な方法は次のとおりです。

id myVar = [someObject someMessage];
.... do something ....;
[myVar release];
return someValue;

取得したリソースをコード内で解放することを覚えておく必要があるという問題は、退屈でエラーが発生しやすいものです。Objective-C は、これをより簡単にすることを目的とした別の概念を導入しています: 自動解放プールです。自動解放プールは、各スレッドにインストールされる特別なオブジェクトです。NSAutoreleasePool を調べると、これらはかなり単純なクラスです。

オブジェクトに「自動解放」メッセージが送信されると、オブジェクトは、この現在のスレッドのスタックにある自動解放プールを探します。将来のある時点で「解放」メッセージを送信するオブジェクトとしてオブジェクトをリストに追加します。これは通常、プール自体が解放されるときです。

上記のコードを次のように書き直して、短く読みやすくすることができます。

id myVar = [[someObject someMessage] autorelease];
... do something ...;
return someValue;

オブジェクトは自動解放されるため、「解放」を明示的に呼び出す必要はなくなりました。これは、一部の自動解放プールが後でそれを行うことがわかっているためです。

うまくいけば、これが役に立ちます。ウィキペディアの記事は、参照カウントについて非常に優れています。自動解放プールの詳細については、こちらを参照してください。また、Mac OS X 10.5 以降用にビルドする場合は、ガベージ コレクションを有効にしてビルドするように Xcode に指示できます。これにより、retain/release/autorelease を完全に無視できます。

于 2008-08-09T03:48:10.417 に答える
6

Joshua (#6591) - Mac OS X 10.5 のガベージ コレクション機能はかなりクールに思えますが、iPhone では利用できません (または、アプリを Mac OS X の 10.5 より前のバージョンで実行したい場合)。

また、ライブラリや再利用される可能性のあるものを作成している場合、GC モードを使用すると、そのコードを使用しているすべての人が GC モードを使用するようにロックされます。メモリを手動で。

于 2008-08-09T03:59:35.683 に答える
6

50 ドルを落として Hillegass の本を入手することを検討する場合を除き、retain/release の詳細については追加しませんが、アプリケーションの開発の非常に早い段階で Instruments ツールを使用することを強くお勧めします (最初の1つ!)。これを行うには、Run->Start with performance tools を実行します。Leaks は利用可能な多くのインストゥルメントの 1 つにすぎませんが、リリースするのを忘れたときに表示するのに役立ちます。どれだけの情報が表示されるかは、非常に気の遠くなるようなものです。しかし、このチュートリアルをチェックして、すぐに始めてください:
COCOA TUTORIAL: FIXING MEMORY LEAKS WITH INSTRUMENTS

実際にリークを強制しようとすることは、リークを防ぐ方法を学ぶためのより良い方法かもしれません! 幸運を ;)

于 2008-12-19T20:04:07.550 に答える
5

マット・ディラードは次のように書いています。

return [[s autorelease] release];

自動解放はオブジェクトを保持しません。Autorelease は、後で解放されるようにキューに入れるだけです。そこにリリースステートメントを入れたくありません。

于 2008-08-09T13:48:50.283 に答える
5

私の通常の Cocoa メモリ管理記事のコレクション:

ココアのメモリ管理

于 2009-01-10T10:59:03.407 に答える
4

iDeveloperTV Network から無料のスクリーンキャストを入手できます。

Objective-C でのメモリ管理

于 2008-12-08T11:00:52.243 に答える
4

NilObject の答えは良いスタートです。手動メモリ管理 ( iPhone で必要)に関する補足情報を次に示します。

あなたが個人的alloc/initにオブジェクトを作成した場合、参照カウントは 1 になります。不要になったオブジェクトは、[foo release]またはを呼び出してクリーンアップする必要があります[foo autorelease]。release はすぐにクリーンアップしますが、autorelease はオブジェクトを autorelease プールに追加し、後で自動的に解放します。

autorelease は主に、問題のオブジェクトを返す必要があるメソッドがある場合に使用します (そのため、手動で解放することはできません。それ以外の場合は nil オブジェクトを返すことになります)。 .

alloc/init を呼び出して取得しなかったオブジェクトを取得した場合 - たとえば、次のようになります。

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

しかし、このオブジェクトにしがみつきたい場合は、[foo preserve] を呼び出す必要があります。そうしないと、取得autoreleasedされて nil 参照を保持する可能性があります(上記のstringWithStringのように)。不要になったらお電話[foo release]ください。

于 2008-08-09T04:25:46.537 に答える
2

上記の回答は、ドキュメントの内容を明確に言い換えています。ほとんどの新しい人が遭遇する問題は、文書化されていないケースです。例えば:

  • Autorelease : ドキュメントによると、「将来のある時点で」リリースがトリガーされます。いつ?!基本的に、コードを終了してシステム イベント ループに戻るまで、オブジェクトが存在することを期待できます。システムは、現在のイベント サイクル後いつでもオブジェクトを解放できます。(Matt が以前に言ったと思います。)

  • 静的文字列: NSString *foo = @"bar";-- それを保持または解放する必要がありますか? いいえ、どうですか

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

    ...

    NSString *foo = [self getBar]; // still no need to retain or release
    
  • 作成規則: あなたが作成した場合は、それを所有し、リリースすることが期待されます。

一般に、新しい Cocoa プログラマーが混乱するのは、どのルーチンがretainCount > 0.

以下は、Cocoa でのメモリー管理のための非常に単純なルールからの抜粋です。

保持カウント ルール

  • 特定のブロック内で、-copy、-alloc、および -retain を使用する場合は、-release および -autorelease を使用する場合と同じにする必要があります。
  • 便利なコンストラクタ (NSString の stringWithString など) を使用して作成されたオブジェクトは、自動解放されたと見なされます。
  • -dealloc メソッドを実装して、所有しているインスタンス変数を解放します

1 番目の箇条書きには、 alloc(またはnew fooCopy) を呼び出した場合、そのオブジェクトに対して release を呼び出す必要があることが示されています。

2 番目の箇条書きは次のように述べています。便利なコンストラクターを使用し、オブジェクトを保持する必要がある場合 (イメージを後で描画する場合など)、それを保持する (そして後で解放する) 必要があります。

3番目は自明です。

于 2008-11-06T03:55:38.047 に答える
1

cocoadev に関する有益な情報もたくさんあります。

于 2008-09-15T20:46:23.170 に答える
0

すでに数人が述べたように、Appleのメモリ管理入門はこれから始めるのに最適な場所です。

私がまだ言及していない便利なリンクの1つは、実用的なメモリ管理です。Appleのドキュメントを読んでみると、そのドキュメントの真ん中にありますが、直接リンクする価値があります。これは、例とよくある間違いを含むメモリ管理ルールの見事なエグゼクティブサマリーです(基本的に、ここで他の回答が説明しようとしているものですが、同様ではありません)。

于 2010-02-06T03:01:11.857 に答える