web-dev-qa-db-ja.com

__weak参照と__block参照の違いは何ですか?

私はXcodeのドキュメントを読んでいますが、ここに私を困惑させるものがあります:

__block typeof(self) tmpSelf = self;
[self methodThatTakesABlock:^ {
    [tmpSelf doSomething];
}];

次は、ドキュメントからコピーされます。

ブロックは、キャプチャする変数への強力な参照を形成します。ブロック内でselfを使用すると、ブロックはselfへの強い参照を形成します。したがって、selfもブロックへの強い参照を持っている場合(通常は)、強い参照サイクルが発生します。このサイクルを回避するには、ウィーク(または__block)上記の例のように、ブロック外の自分自身への参照。

弱点(または__block) '意味?

__block typeof(self) tmpSelf = self;

そして

__weak typeof(self) tmpSelf = self;

ここでもまったく同じ?

ドキュメントで別の部分を見つけました:

注:ガベージコレクション環境では、__weakおよび__blockを変数に変更すると、ブロックは、それが生存していることを保証しません。

だから、私は完全に困惑しています。

77
HanXu

__blockに関するドキュメントから

__block変数は、変数の字句スコープと、変数の字句スコープ内で宣言または作成されたすべてのブロックおよびブロックコピーの間で共有されるストレージに存在します。したがって、フレーム内で宣言されたブロックのコピーがフレームの終わりを超えて存続する場合(たとえば、後で実行するためにどこかにキューイングされることにより)、ストレージはスタックフレームの破壊に耐えます。特定のレキシカルスコープ内の複数のブロックは、共有変数を同時に使用できます。

__weakに関するドキュメントから

__weakは、参照されるオブジェクトを存続させない参照を指定します。オブジェクトへの強参照がない場合、弱参照はnilに設定されます。

そのため、それらは技術的に異なるものです。 __blockは、外部スコープからブロックスコープへの変数のコピーを停止します。 __weakは自己区切りの弱いポインターです。

あなたの場合、彼らは(ほぼ)同じことをするからです。唯一の違いは、ARCを使用しているかどうかです。プロジェクトがARCを使用し、iOS4.3以上のみを対象としている場合は、__ weakを使用します。グローバルスコープ参照が何らかの形でリリースされる場合、参照がnilに設定されるようにします。プロジェクトがARCを使用していないか、古いOSバージョン用である場合は、__ blockを使用します。

ここには微妙な違いがあります。必ず理解してください。

編集:パズルの別のピースは__unsafe_unretainedです。この修飾子は__weakとほぼ同じですが、4.3以前のランタイム環境用です。ただし、nilに設定されておらず、ハンギングポインターが残る可能性があります。

106
Paul de Lange

手動参照カウントモードでは、__ block id x; xを保持しないという効果があります。 ARCモードでは、__ block id x;デフォルトではxを保持します(他のすべての値と同様)。 ARCで手動参照カウントモードの動作を取得するには、__ unsafe_unretained __block id x;を使用できます。ただし、__ unsafe_unretainedという名前が示すように、保持されない変数は危険です(ぶら下がる可能性があるため)。したがって、推奨されません。 2つの優れたオプションは、__ weakを使用するか(iOS 4またはOS X v10.6をサポートする必要がない場合)、または__block値をnilに設定して保持サイクルを中断することです。

Appleドキュメント

5
Andrei Shender

__block__weakに関する他の回答のほかに、シナリオで保持サイクルを回避する別の方法があります。

@weakify(self);
[self methodThatTakesABlock:^ {
    @strongify(self);
    [self doSomething];
}];

@ Weakify @Strongifyマクロの詳細

0
Jun Jie Gan

ブロック内でselfを使用する場合、selfを保持する可能性があるため、__ blockではなく__ weakを使用する必要があります。

強い自己が必要な場合は、次のように使用できます。

__weak typeof(self) *weakSelf = self;
[self methodThatTakesABlock:^{
    if (weakSelf) {
        __strong typeof(self) *strongSelf = weakSelf;
        [strongSelf doSomething];
    }
}];
0
david72