1

ARCを使用しています。
オブジェクトの割り当てを解除する必要があることを表明するために、次のコードを記述したことがあります。

__weak weakVariableOrProperty = someObject;
....

someObject = nil;
// or someObject = anotherObject;
....

if (weakVariableOrProperty) {
    @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Object not deallocated" userInfo:nil];
}

たとえば、このコードを使用して、新しいViewControllerを作成する前にViewControllerの割り当てが解除されているかどうかを確認します。

最後の強い変数またはプロパティがnilまたは別のオブジェクトに設定された直後に、弱い変数または弱いプロパティがnilに設定されていると思います。

そして、このコードは私が今まで期待したように機能しています。

弱い変数またはプロパティを使用してオブジェクトの割り当てが解除されているかどうかを確認するのは、一般的に使用される手法ですか?
このコードが将来問題を引き起こす可能性はありますか?

4

3 に答える 3

2

最後の強い変数またはプロパティがnilまたは別のオブジェクトに設定された直後に、弱い変数または弱いプロパティがnilに設定されていると思います。

オブジェクトが自動解放される可能性があるため、これは正確には当てはまりません。この場合、最後の強力な参照がなくなっている可能性がありますが、インスタンスの参照カウントは正のままです。そのような場合、自動解放プロセスが実行されるまで、__weak参照は削除されません。nil

弱い変数またはプロパティを使用して、オブジェクトの割り当てが解除されているかどうかを確認するのは、一般的に使用されている手法ですか?

ARCはObjectiveCにとって比較的新しいものであるため、この手法が広く普及していることを真剣に疑っています。ただし、この手法は有効であるように見えます。

このコードが将来問題を引き起こす可能性はありますか?

ARC仕様では参照のタイミングについて特定の保証がなく、nilコンパイラがARCオブジェクトに送信するメッセージのシーケンスretainとメッセージを最適化できるため、これを推測するのは非常に困難です。release

于 2012-10-16T14:25:36.403 に答える
1

説明コードは競合状態になりがちです。

条件が評価された後、のオブジェクトはweakVariableOrProperty解放される可能性があります(弱参照によってのみ参照されるため) 。ifこれを回避するには、通常の変数を導入し、に設定してweakVariableOrProperty、代わりにチェックしnilます。

とはいえ、@ dasblinkenlightが言うように、オブジェクトがいつなくなるかを正確に判断するのは困難です。参照カウントシステムでは、他に何が保持されているのかわかりません。確認した直後に消える場合があります。システムが物事をかき乱していないことを知っているように、環境を十分に制約できるはずですが、自動解放と弱参照の両方が物事を複雑にします。

これを解決する最善の方法は、オブジェクトの存続期間を明確に定義することです。つまり、永久に存続しないビューコントローラー、明示的に削除するように指示するビューコントローラーなどです。

于 2012-10-16T14:56:53.363 に答える
0

そこで、この手法を使用して、オブジェクトが常にバックグラウンドスレッドで割り当て解除されるようにしました。一部のクラスの[dealloc]は適度に重いため、長い時間(数十ミリ秒)かかる可能性があり、メインスレッドがわずかにフリーズしていました。

これらの重いオブジェクトはすべて、メインスレッドで解放される前に配列に追加し、後でバックグラウンドスレッドでその配列を調べて、配列から削除することにしました。配列は、バックグラウンドスレッドで配列から削除できるようになるまで、retainCountを存続させ、メインスレッドで[dealloc]のコストが発生しないことを保証できると考えられていました。

これを行うために、私は以下のコードを持っていました:

while([objectsToDealloc count] && /* other conditions to prevent infinite loop */){
    __weak id ref = [objectsToDealloc lastObject];
    [objectsToDealloc removeLastObject];
    @synchronized(ref){
        // synchronising on ref will retain it if possible.
        // so if its still around,that means we didn't dealloc it
        // like we were asked to.
        // so insert it back into our array. once the object is deallocd
        // it won't be able to be synchronized, because the weak ref will
        // be nil
        if(ref){
            [objectsToDealloc insertObject:ref atIndex:0];
        }
    }
}

配列に最後の参照が含まれていなかった場合(またはオブジェクトに保留中の自動解放があった場合など)、弱参照がゼロにならないという考え方でした。次に、オブジェクトで@synchronizeします-同期されたブロックは、同期されているオブジェクトを保持+解放します-これにより、refそのブロックの間、が存続することが保証されます。それがゼロだった場合、それは割り当てが解除されていました。nilでない場合は、配列に追加し直して、後でもう一度確認する必要があります。

過去数週間にわたってこのコードでテストした後、割り当て解除されたオブジェクトをチェックするためにこの戦略を推奨することはできません。正確な理由はまだわかりませんが、オブジェクトのロックが解除されることはめったにありませんが、refはまだnilになっていないため、無効なオブジェクトを配列に追加し直します。

デバッガーでこれを1回だけキャッチしましたが、クラッシュログが数回発生しています。上記のコードはそれから保護する必要がありますが、以下で「nil」が私の配列に含まれることがわかります。

NSArray内のnil

繰り返しになりますが、オブジェクトの割り当てが解除されたとき/かどうかを検出するためにこの手法を使用せず、代わりにオブジェクトのグラフと関係を明確にすることに注力することをお勧めします。

于 2014-09-18T04:31:55.863 に答える