2009-08-02 10 views
25

私はメモリマネージドコードが新ですが、私はかなりうまく考えています。Objective Cリリース、オートリリース、データタイプ

私のアプリケーションをXCodeのリークツールで撮ると、私は自分のカスタムオブジェクトをクリーンアップしなければならないことに気付きましたが、例えば動的に作成された配列は除かれていました。私が使用した配列を(保持する)プロパティとして解放します。

は、それから私は、独特の何かに気づいた:私はこのように初期化され、特定のアレイ上にリークなっていた。

NSMutableArray *removals = [NSMutableArray new]; 

ではなく、同様のもの今

NSMutableArray *removals = [NSMutableArray arrayWithCapacity:9]; 

を、1を設定した理由を「新しい」とは0〜99の項目を持つことができるということですが、私が知っているもう1つの項目は常に9になるはずです。両方の配列が後でユーザーのやりとりに基づいて同じメソッドに渡されるため、私がメソッドの終わりに解放しなかった場合、または私が行った場合は例外が発生しました!

私は

NSMutableArray *removals = [NSMutableArray arrayWithCapacity:99]; 

に最初の配列を変更し、私はリークを取得していないし、何かを解放する必要はありません。誰でも説明できますか?

答えて

65

memory management rulesに述べたように、あなたは+alloc+new-copy、または-mutableCopyで作成したオブジェクトがあるとき、あなたはそれを所有し、いくつかの時点でそれを解放する責任があります。 (実際には、+new[[MyClass alloc] init]の省略形です)上記のとおり、[NSArray new]で配列を作成すると、それを解放せずにメモリリークが発生します。ただし、このオブジェクトを適切に処理すると、通常はある時点で解放することができます。たとえば:

  • は、アレイは、アレイを作成する方法から呼び出されを用いる方法であれば、あなたはそれが使用された後に、配列を解放することができるはずです。内部メソッドが配列の周囲のより永続的な参照を保持する必要がある場合、そのメソッドは-retain、そして最終的に-releaseをオブジェクトに送信します。たとえば、次のように

    - (void)myMethod { 
        NSArray *removals = [NSArray new]; 
        // ... 
        [someObject someOtherMethod:removals]; 
        [removals release]; 
    } 
    
  • あなたがオブジェクトの-init方法で配列を作成した場合、オブジェクトが破棄されると、その後、-dealloc方法はそれを解放することができます。

  • アレイを作成する必要がある場合は、をメソッドから返すを返すと、自動リアーニングが発明された理由がわかりました。メソッドの呼び出し元は、+alloc+new-copy、または-mutableCopyのメソッドではないため、オブジェクトを解放する責任はありませんが、最終的に解放する必要があります。この場合、返す前にオブジェクトの-autoreleaseを手動で呼び出します。たとえば、次のよう

あなたが結果を解放する必要はありませんので、あなたは、「特別」のいずれかの方法を呼び出すされていない+arrayWithCapacity:を経由して、アレイを作成

- (NSArray *)myMethod { 
    NSArray *removals = [NSArray new]; 
    // ... 
    return [removals autorelease]; 
} 
。これはおそらく最後の例のように、 -autoreleaseで実装されていますが、必ずしもそうではありません。 (ちなみに、 [NSMutableArray array]の空のオートリリース済みNSMutableArrayを作成することもできますが、メソッドはNSArrayにありますので、NSMutableArrayのドキュメントには表示されませんが、NSMutableArrayクラスに送信すると変更可能な配列が作成されます)あなたのメソッドから配列を返すことになりますが、これは [[[NSMutableArray alloc] init] autorelease]の略語として使うことができますが、これは単なるショートカットです。ただし、多くの状況では、 -initまたは +newというオブジェクトを作成し、適切なタイミングで手動で解放することができます。

4

ココアは特定の命名規則を使用しています。 alloc、new、またはcopyで始まるものは、retainCountが1のものを返し、解放する必要があります。関数が返すその他のものは、バランスのとれたretainCountを持っています(それは他のものによって保持されているか、保持され、解放されている可能性があります)。だから、

NSMutableArray *removals = [NSMutableArray new]; 

が1のretainCountを持ち、:メソッドはアロケーションが付いていないので

NSMutableArray *removals = [NSMutableArray arrayWithCapacity:99]; 

または

NSMutableArray *removals = [NSMutableArray array]; 

にはない、新しいですかコピー。これはすべてメモリ管理documentationに記載されています。特に:あなたはその名を 、「アロケーション」または「新しい」または は、「コピー」(例えば、アロケーションが含まれ、 でnewObjectで始まるメソッドを使用して作成し 場合

あなたは、オブジェクトの所有権を取得しますまたはmutableCopy)、または の場合は保持メッセージを送信します。 リリースまたは自動リリースを使用して所有しているオブジェクトの所有権を放棄する責任を負います。それ以外の時間をお持ちの場合は 、 はリリースしないでください。

+1

**これらのメソッドのすべて**は、保持カウント1のオブジェクトを返します。違いは、あなたがオブジェクトを所有しているため、オブジェクトをリリースする必要があります。それを解放する必要はありません(しかし、現在のコールチェーンを過ぎていることを期待することはできません)。 – Chuck

+2

厳密に言えば、その実装の詳細はありません。多くの場合、保持数の異なるものが返されます。たとえば、[= UIImage imageNamed:]は、キャッシュされたイメージを再利用できるため、非常に大きなlargeCountを持つものを返す可能性があります。 –

+1

さて、はい、保持カウント自体は実装の詳細です。 Appleのドキュメントはそれほど多くのことを言います。上記のすべてのケースでは、現在のバージョンのOS Xでは、この実装の詳細の値は1です。 – Chuck

7

これは物事がシーンの背後に実装する方法である:配列のみが割り当てられ、あなたがそれをデ割り当てるための責任がありますされた最初のケ​​ースで

+(NSMutableArray*) new 
{ 
    return [[NSMutableArray alloc] init]; 
} 

+(NSMutableArray*) arrayWithCapacity:(NSNumber)capacity 
{ 
    return [[NSMutableArray alloc] initWithCapacity:capacity] **autorelease**]; 
} 

。逆にarrayWithCapacityはあなたのために自動リリースされています。割り当てを解除しなくてもリークは発生しません。