4

配列を個別のオブジェクトに「アンパック」するための PHP の list() 関数のように機能する NSArray のちょっとした便利なメソッドを書きました。

- (void)unpackInto:(__strong id *)obj1, ...
{
    __strong id *idPtr;
    va_list args;
    va_start(args, obj1);

    idPtr = obj1;
    NSUInteger idx = 0;
    NSUInteger count = [self count];
    while (idPtr != NULL && idx < count) {
        *idPtr = [self objectAtIndex:idx];

        // Increment the args and idx count
        idx++;
        idPtr = va_arg(args, __strong id *);
    }
}

私はもともと持っていまし__autoreleasing id *たが、内容を一時的なローカルスタック変数に解凍するために、独自の自動解放プールを持つスレッドでこのメソッドが呼び出されたときに (問題がある場合は実際には 2 回)、EXC_BAD_ACCESS の問題に遭遇しました。メイン スレッドが戻ってきて、内容を (再び) 自動解放しようとすると、EXC_BAD_ACCESS がスローされました。

この場合、これらのブリッジング パラメーターを使用してロジックに従うことができる人はいますか? __strong少し目立たないが、同じように邪悪な双子のいとこであるメモリリークにつながるのではないかと心配しています...

4

1 に答える 1

2

私はあなたのソース コードを見たことがありませんが、保持/解放/自動解放プールよりも所有権の観点から考えれば、ほとんどの ARC の問題に対する答えは解決できます。誰が配列を所有しており、誰がアンパックされたポインターを所有しているかを答えてみてください。私があなたを正しく理解していれば、あなたの呼び出し方法は次のようになります

  NSArray *arr = [NSArray arrayWithObjects:@"a", @"b", @"c", @"d", nil];

  NSString *a, *b, *c, *d;
  [arr unpackInto:&a, &b, &c, &d, nil];

アンパックされた変数にアクセスする前に、配列の割り当てが解除されていますか? __autoreleasing は、可変引数ポインターに値を「保持」しないことに注意してください。したがって、配列の割り当てが解除されると、ポインターはガベージになります。私の推測では、あなたの EXC_BAD_ACCESS は、メイン配列の割り当てが解除されるためです。

__strong は、参照によって戻るときに使用しないでください。保持カウントは増加しません。これらの変数が呼び出し元のメソッドで解放されることを ARC に知らせる方法はありません。そのため、ARC はそのスコープの後にそれらをリリースします。割り当てられたオブジェクトを呼び出し元のメソッドに渡し、呼び出し元のメソッドの割り当てを解除させる唯一の方法は、init-family に属するメソッドからオブジェクトを返すことです。メソッドの境界を越えて値を返す場合、ARC はメソッド ファミリ (またはマクロ NS_RETURNS_RETAINED/NS_RETURNS_NON-RETAINED) を使用して、誰がポインターを「所有」しているかを判断します。

const ポインター (非ライトバック ポインター) を渡す場合、参照渡しに __strong を使用できます。

LLVM ドキュメントの詳細については、 http: //clang.llvm.org/docs/AutomaticReferenceCounting.html#ownership.restrictions.pass_by_writeback をご覧ください。

于 2012-02-26T02:01:28.960 に答える