4

ARCの下に自動解放プールを配置せずにこのコードを実行しています:

- (NSString*) outName {
    if (!outName) {
        outName = [[NSString alloc] initWithFormat:@"whatever"]; // or stringWithFormat
    }
    return outName;
}

デバッガーは、 プールが配置されていない状態で毎回単一のインスタンスをリークしていると言います。 outName

コードを次のように変更しても、これは発生しません

- (NSString*) outName {
    if (!outName) {
        outName = @"whatever";
    }
    return outName;
}

私にはできません(この例は明らかに単純化されています)。また、呼び出し元のコードに自動解放プールを作成すると、リークメッセージが消えます(これは避けたいです)。

strongなぜARCは、プロパティに保持されているこのオブジェクトの自動リリースを主張しているのですか?そしてもっと重要なことに、どうすればこの警告を回避できますか?

4

4 に答える 4

2

これは所有権の問題です。

最初に自分で割り当てたNSStringについて話しましょう。オブジェクトを割り当てると、ヒープ内のメモリはそのオブジェクト用に予約されます(allocWithZone:を別の場所に割り当てない限り)。保持カウントは暗黙的に1であり、オブジェクトを所有します。つまり、完了時にオブジェクトを解放する責任があります。そのオブジェクトへのポインタを返す場合、つまりそのオブジェクトを返す場合、オブジェクトがリークしないようにする責任を完全に放棄することはありません。保持カウントが0になり、そのオブジェクトの割り当てが解除されるため、解放できません。自動解放し、実行ループの最後(またはそれより早く)にオブジェクトが解放され、場合によっては割り当てが解除されるようにします。返されたオブジェクトがより長く存続する必要がある場合、呼び出し元の関数は返されたオブジェクトを保持する責任があります。

自動解放プールがないと、指定されたautoReleasePoolがnullであるため、リークが発生します(nullのメッセージを表示することは問題ありません。そのため、リークするだけでなく、クラッシュするだけではありません)。

コンパイラがその文字列用にプログラムメモリを予約しているため、@ "whatever"が修正された例はリークせず、-releaseはそれらに影響を与えません。同じことがいくつかの低い値のNSNumberにも当てはまります。

Jamesが言ったように、ARCは保持リリースと自動リリースの概念を削除しません。

編集:outNameはivar / propertyとしてどのように宣言されますか?

于 2012-06-25T15:03:46.387 に答える
0

Jaredの答えは良いですが、ARCが機能する方法の一部は、命名規則を使用することです。のメソッド名はoutName、値を返すことを意味するautoreleasedため、de-ARC-ifierがあった場合、最後の行は次のようになります。

return [[outName retain] autorelease];

明らかに、これには自動解放プールが必要です。

定数を返すため、これは2番目の例では発生しません。したがって、retain/autoreleaseは最適化されます。

于 2012-06-25T15:18:40.037 に答える
0

ARCがivar(または任意のオブジェクト)を呼び出し元のメソッドに返す場合、現在のRunLoopが終了する前に解放されないことを保証する必要があります。プログラマーとしては、リリースされることは決してないことを知っていますが、ARCはアルゴリズムによる保証(ベストプラクティス)に依存しています。変数が定数( NARCでインスタンス化されていない)を指していretain] autorelease] ない限り、 ARCは呼び出します。したがって、解放されるリスクはありません。

この警告を避けてはいけません。コードを修正する必要があります。自動解放プールを追加できます。これを実行したくない場合は、もう1つの方法は、ivarを使用するロジックを実際にivarを保持しているオブジェクトにプッシュダウンすることです。

于 2012-07-09T05:10:56.173 に答える
-1

奇妙なことに、私は私が使用しているのと非常によく似た方法を持っており、それは漏れません。次のようになります。

-(NSString *) dataFilePath {

    NSString *appendPath;
    if (isPowerMode==YES) {
        appendPath = kDataFileNamePower;
    } else {
        appendPath = kDataFileNameClassic;
    }

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    return [documentsDirectory stringByAppendingPathComponent:appendPath];
}       

したがって、そこから先に進むと、メソッドの先頭で空のNSStringポインターを宣言し、outNameの代わりにそれを入力して返す必要があります。

于 2012-06-25T14:51:03.680 に答える