4

RetainCount == 悪い

retainCountはタブーであり、信頼性が低く、予測不可能であり、一般的に使用すべきではありません。コードのどこにも使用していませんが、興味深い方法で使用している 1 つのクラスで見ました。

スレッドがキャンセルされるまで無期限に実行されるスレッドを実行するクラスがあります。問題は、スレッドが所有者の保持カウントを増やすことです。私の場合は、それをインスタンス化したクラスです。そのため、そのクラスを使い終わったとしても、クラスを管理している誰かがスレッドをシャットダウンすることを知っていない限り、そのインスタンスはまだぶらぶらしています。これは 1 つの解決策ですが、これがコードで見つけたものです。

- (oneway void)release
{
    // This override allows allows this object to be dealloced 
    // by shutting down the thread when the thread holds the last reference.
    // Otherwise, the object will never be dealloc'd
    if (self.retainCount == 2)
    {
        [self quitDispatchThread];
    }

    [super release];
}

これは賢い解決策ですが、どう考えればよいかわかりません。クラスの release をオーバーライドし、retain カウントが 2 かどうかを確認します。つまり、オブジェクトを存続させているのはスレッドだけかどうかを確認します(retain カウントが 2 から 1 に減らされようとしているため)。 ) スレッドを終了します (quitDispatchThreadスレッドが終了するまでブロックします)。

そう...

1 かどうかを確認するために、retainCount を信頼できますか?

retainCountそこにいくつかの自動リリースがあるかどうかわからないので、通常、人々は近づかないようにと言います。ただし、retainCount が 1 の場合、スレッドだけがそれを維持しているという事実がわかり、自動解放などが原因でretainCount がオフになる可能性があることを心配する必要はありません...

このコードの何が問題になっていますか?

削除しようとしましたが、実際には理にかなっているようです。他のオブジェクトは、私のクラスがスレッドを実行していることを認識する必要はありません。他のオブジェクトretainや、スレッドを所有しているオブジェクトreleaseでさえもautorelease、スレッドをシャットダウンすることを心配する必要はありません。

このコードは実際にはすっきりしていて、私は驚いています。

編集 :: NSThread がオブジェクトを保持している

NSThread を使用しているため、オブジェクトの保持カウントが増加しています。私のオブジェクトは でtargetselectorはスレッドが実行されるメソッドです。

initWithTarget:セレクター:オブジェクト:

指定された引数で初期化された NSThread オブジェクトを返します。

  • (id)initWithTarget:(id)ターゲットセレクター:(SEL)セレクターオブジェクト:(id)引数

パラメーター

目標

selector で指定されたメッセージの送信先オブジェクト。

セレクタ

ターゲットに送信するメッセージのセレクター。このセレクターは引数を 1 つだけ受け取る必要があり、戻り値を持たない必要があります。

口論

ターゲットに渡される単一の引数。ゼロかもしれません。

戻り値

指定された引数で初期化された NSThread オブジェクト。

討論

ガベージ コレクションされていないアプリケーションの場合、メソッド セレクターは、新しく切り離されたスレッドの自動解放プールを設定し、終了する前にそのプールを解放する役割を果たします。ガベージ コレクションされたアプリケーションは、自動解放プールを作成する必要はありません。

オブジェクトのターゲットと引数は、切り離されたスレッドの実行中に保持されます。それらは、スレッドが最終的に終了するときに解放されます。

4

2 に答える 2

6

retainCountはタブーであり、信頼性が低く、予測不可能であり、一般的に使用すべきではありません。

retainCountCocoa フレームワークなど、オブジェクトが不透明なコードを通過しない IFFの値に依存できます。実際には、これを達成することはほとんど不可能であるため、警告が表示されます。Cocoa の内部では、オブジェクトの受け渡し、保持、解放、および autorelease プールへの配置が、さまざまな理由で何度も行われる可能性があり、任意の時点でその絶対値に依存することはできません。

キャッチは、スレッドが所有者の保持カウントを増やすことです。私の場合は、それをインスタンス化したクラスです。

それが保持サイクルです。ここでの答えは、そのサイクルを断ち切る方法を見つけることであり、参照カウントのメカニズムを覆すことではありません。スレッドまたは所有しているオブジェクトのいずれかが、スレッドが実行している作業が完了した (または時期尚早に停止する必要がある) ことを認識している場合、解放のにいくつかのポイントが必要です。

所有オブジェクトは、スレッドが実行している作業へのクライアント コードのインターフェイスであるように思えます。この所有オブジェクトには、その所有者がオブジェクトを解放する前に呼び出す必要がある (および「呼び出す必要がある」と文書化されている) 「すぐにシャットダウン」するメソッドが必要です。そのシャットダウン方法では、スレッドを解放することでサイクルを中断できます。

スレッドがその作成者を保持しているために何が起こっているのか正確にはわかりません (サイクルは、所有モデルに何かNSThread問題があることを明確に示しています) - andを使用していると思いますがinitWithTarget:...、ターゲットはオブジェクトの作成/所有。これは、標準の MVC パターンを少し混同したものです。スレッドの所有者は「コントローラー」であり、スレッド自体 (およびそれが実行するコード) は「モデル」に近いものです。

つまり、コントローラーにスレッドのコードを含めるべきではありません。スレッドのコードを別のオブジェクトに分解して、ターゲットとして使用することをお勧めします。次に、コントローラー オブジェクトはスレッド自体と「作業」ターゲット オブジェクトの両方を所有し、どちらもコントローラーを所有しません。ほら、サイクルがありません!

于 2012-04-05T16:47:30.070 に答える
2

いいえ。あなたは、そのゲートに「KeepOut」という記号が公に付けられている抽象化された実装に依存しています。

独自のメモリと実装を使用して依存関係を管理するだけです。これには、完了/破棄フェーズのivarおよび/またはメソッドが含まれる場合があります。

以下のドキュメントも参照してくださいrelease

リリース

受信者の参照カウントを減らします。(必要)

- (oneway void)release

討論

参照カウントが0に達すると、受信者にdeallocメッセージが送信されます。

このメソッドを実装するのは、独自の参照カウントスキームを定義する場合のみです。このような実装では、継承されたメソッドを呼び出さないでください。つまり、superへのリリースメッセージを含めるべきではありません。

プログラムが複数のリリースで正しく動作することを確認したい場合は、今すぐ変更することをお勧めします。

于 2012-04-05T17:09:24.140 に答える