回答:
retain
and から始めましょうrelease
。autorelease
基本的な概念を理解すれば、本当に特別なケースです。
Cocoaでは、各オブジェクトは参照されている回数を追跡します(具体的には、NSObject
基本クラスがこれを実装します)。retain
オブジェクトを呼び出すことにより、参照カウントを1つ増やしたいことを伝えます。を呼び出すことでrelease
、手放すオブジェクトを指定し、その参照カウントをデクリメントします。を呼び出した後release
、参照カウントがゼロになった場合、そのオブジェクトのメモリはシステムによって解放されます。
基本的な方法この異なるのmalloc
とfree
、任意のオブジェクトが、あなたは彼らが使用していたメモリを解放してきたので、クラッシュ、システムの他の部分を心配する必要はないということです。全員がルールに従って遊び、保持/解放していると仮定すると、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
が呼び出されると、現在のスレッド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];
}
これらすべてが少し混乱していることに気づきました-ある時点で、それはクリックします。ここにあなたを始めるためのいくつかの参照があります:
NSString* s = [[NSString alloc] initWithString:@"Hello World"];
(あなたが書いたように)自動解放されたオブジェクトを返す場合、なぜ私はaを実行してreturn [s autorelease];
それを「自動解放」に設定する必要があるのreturn s
ですか?
[[NSString alloc] initWithString:@"Hello World"]
自動解放されたオブジェクトを返しません。alloc
呼び出されるたびに、参照カウントは1に設定され、解放されることを確認するのはそのコードの責任です。[NSString stringWithString:]
コールは、他の一方で、ない自動解放オブジェクトを返します。
保持/解放のプロセスを理解している場合は、確立されたCocoaプログラマには明らかである2つのゴールデンルールがありますが、残念ながら、初心者にはこれが明確に記述されていることはほとんどありません。
オブジェクトを返す関数を持っている場合alloc
、create
またはcopy
その名前でそのオブジェクトは、あなた次第です。[object release]
使い終わったら電話する必要があります。またはCFRelease(object)
、それがCore-Foundationオブジェクトの場合。
名前にこれらの単語の1つが含まれていない場合、オブジェクトは他の誰かに属しています。[object retain]
関数の終了後もオブジェクトを保持する場合は、呼び出す必要があります。
自分で作成した関数では、この規則にも従うことができます。
(Nitpickers:はい、残念ながら、これらのルールの例外であるいくつかのAPI呼び出しがありますが、まれです)。
デスクトップ用のコードを作成していて、Mac OS X 10.5をターゲットにできる場合は、少なくともObjective-Cガベージコレクションの使用を検討する必要があります。開発の大部分が本当に簡素化されます—それが、Appleがそもそもの開発に全力を注いで、うまく機能させる理由です。
GCを使用しない場合のメモリ管理ルール:
+alloc/+allocWithZone:
、+new
、-copy
または-mutableCopy
かあれば-retain
、オブジェクトを、あなたはそれの所有権を取っているし、それが送信されることを確認しなければなりません-release
。-release
。-release
、自分で送信するか、オブジェクトを送信することができます。プールが空になる-autorelease
と、現在の自動解放プールがそれを-release
(受信ごとに1回-autorelease
)送信します。-autorelease
Cocoaのイベント処理を囲む自動解放プールがあるため、通常、オブジェクトが現在のイベントの長さにわたって存続することを保証する方法として使用されますが、後でクリーンアップされます。Cocoaでは、自動解放されたオブジェクトを呼び出し元に返す方が、呼び出し元自体が解放する必要があるオブジェクトを返すよりもはるかに一般的です。
Objective-Cは参照カウントを使用します。これは、各オブジェクトに参照カウントがあることを意味します。オブジェクトが作成されると、参照カウントは「1」になります。簡単に言えば、オブジェクトが参照される(つまり、どこかに格納される)と、オブジェクトは「保持」され、参照カウントが1つ増えます。オブジェクトが不要になると、「解放」されます。つまり、参照カウントが1つ減ります。
オブジェクトの参照カウントが0の場合、オブジェクトは解放されます。これは基本的な参照カウントです。
一部の言語では、参照は自動的に増減されますが、objective-cはそれらの言語の1つではありません。したがって、プログラマーは保持と解放を担当します。
メソッドを記述する一般的な方法は次のとおりです。
id myVar = [someObject someMessage];
.... do something ....;
[myVar release];
return someValue;
コード内で取得したリソースを解放することを覚えておく必要があるという問題は、面倒でエラーが発生しやすいものです。Objective-Cは、これをより簡単にすることを目的とした別の概念、Autorelease Poolsを導入しています。自動解放プールは、各スレッドにインストールされる特別なオブジェクトです。NSAutoreleasePoolを調べれば、これらはかなり単純なクラスです。
オブジェクトが送信された「autorelease」メッセージを受け取ると、オブジェクトはこの現在のスレッドのスタックにある自動解放プールを探します。オブジェクトをリストに追加して、「解放」メッセージを将来のある時点で送信します。これは通常、プール自体が解放されるときです。
上記のコードを例にとると、次のように記述して、コードを短く読みやすくすることができます。
id myVar = [[someObject someMessage] autorelease];
... do something ...;
return someValue;
オブジェクトは自動解放されるため、「解放」を明示的に呼び出す必要はなくなりました。これは、一部の自動解放プールが後でそれを実行することがわかっているためです。
うまくいけば、これが役立ちます。ウィキペディアの記事は、参照カウントに関してかなり優れています。自動解放プールの詳細については、こちらを参照してください。また、Mac OS X 10.5以降用にビルドする場合は、ガベージコレクションを有効にしてビルドするようにXcodeに指示できるため、保持、解放、自動解放を完全に無視できます。
Joshua(#6591)-Mac OS X 10.5のガベージコレクションはかなりクールに見えますが、iPhoneでは使用できません(または、10.5より前のバージョンのMac OS Xでアプリを実行したい場合)。
また、ライブラリや、再利用される可能性のあるものを作成している場合、GCモードを使用すると、コードを使用しているすべてのユーザーがGCモードも使用するようにロックされます。手動でメモリ。
いつものように、人々が参考資料を書き直そうとするとき、彼らはほとんど間違いなく何か間違いをしたり、不完全な説明を提供したりします。
Appleは、Cocoaのメモリ管理プログラミングガイドでCocoaのメモリ管理システムの完全な説明を提供しています。その最後には、メモリ管理ルールの簡潔で正確な概要があります。
$ 50を下げてHillegassの本を入手することを検討する場合を除いて、保持/リリースの詳細には追加しませんが、アプリケーションの開発の非常に早い段階でInstrumentsツールを使用することを強くお勧めします(最初の1つ!)。これを行うには、実行->パフォーマンスツールで開始します。入手可能な多くの楽器の1つであるLeaksから始めますが、リリースするのを忘れたときに表示するのに役立ちます。どれだけの情報が提示されるかは気の遠くなるようなものです。しかし、このチュートリアルをチェックして、すぐに始めてください:
COCOAチュートリアル:メモリーリークをインストゥルメントで修正する
実際にリークを強制しようとすることは、リークを防ぐ方法を学ぶより良い方法かもしれません!幸運を ;)
return [[s autorelease] release];
自動解放はオブジェクトを保持しません。自動解放は、後で解放するためにキューに入れるだけです。あなたはそこにリリース声明を持ちたくありません。
NilObjectの答えは良い出発点です。手動のメモリ管理に関する補足情報をいくつか示します(iPhoneで必要)。
個人的alloc/init
にオブジェクトの場合、参照カウントは1になります。[foo release]
またはを呼び出して、不要になったオブジェクトをクリーンアップする必要があります[foo autorelease]
。releaseはすぐにクリーンアップしますが、autoreleaseはオブジェクトをautoreleaseプールに追加し、後で自動的に解放します。
autoreleaseは主に、問題のオブジェクトを返す必要があるメソッドがある場合(手動で解放できない場合は、nilオブジェクトを返すことになります)ですが、それを保持したくない場合にも使用します。 。
取得するためにalloc / initを呼び出さなかったオブジェクトを取得した場合-たとえば:
foo = [NSString stringWithString:@"hello"];
しかし、このオブジェクトを使い続けたい場合は、[foo keep]を呼び出す必要があります。それ以外の場合は、取得可能でありautoreleased
、nil参照を保持します(上記のstringWithString
例のように)。不要になったらに電話してください[foo release]
。
上記の答えは、ドキュメントが言っていることの明確な言い直しを与えます。ほとんどの新しい人々が遭遇する問題は、文書化されていないケースです。例えば:
自動リリース:「将来のある時点で」リリースをトリガーするとドキュメントは言っています。いつ?!基本的に、コードを終了してシステムイベントループに戻るまで、オブジェクトが存在することを期待できます。システムは、現在のイベントサイクルの後、いつでもオブジェクトを解放できます。(マットは以前に言ったと思います。)
静的文字列: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メソッドを実装して、所有するインスタンス変数を解放します
最初の箇条書きは言う:(alloc
またはnew fooCopy
)を呼び出した場合、そのオブジェクトでreleaseを呼び出す必要があります。
2番目の箇条書きは、便利なコンストラクタを使用していて、オブジェクトをぶらぶらする必要がある場合(後で描画されるイメージの場合のように)、それを保持(そして後で解放)する必要があります。
3番目は自明です。
cocoadevに関するたくさんの良い情報: