15

イベント処理を含むAPIを作成していますが、ハンドラにブロックを使用できるようにしたいと考えています。コールバックは、しばしば自己にアクセスしたり変更したりしたいと考えます。 ARCモードでは、Clangはselfを参照するブロックが保持サイクルを作成する可能性があることを警告します。これは一般的に続行しておきたい有用な警告のようです。自己参照ブロックのアーク保持サイクル警告をコンパクトに無効にする

ただし、このAPIの部分では、コールバックとそのオブジェクトを含むライフサイクルのライフサイクルは外部的に維持されます。私は、オブジェクトの割り当てを解除する必要があるサイクルを中断することができることを知っています。

ファイルごとに#pragma clang diagnostic ignored "-Warc-retain-cycles"で保持周期の警告をオフにすることはできますが、ファイル全体の警告は無効になります。私はその警告の周りに#pragma clang diagnostic pushpopのブロックを囲むことができますが、それはブロックを醜いものにします。

自分自身を直接参照するのではなく、selfを指す__weak変数を参照して警告を出すこともできますが、ブロックを使用するのがはるかに面白くありません。それは、ネストされたことはできません、

#define OBSERVE(OBJ, OBSERVEE, PATH, CODE) \ 
[(OBJ) observeObject:(OBSERVEE) forKeyPath:(PATH) withBlock:^(id obj, NSDictionary *change) { \ 
_Pragma("clang diagnostic push") \ 
_Pragma("clang diagnostic ignored \"-Warc-retain-cycles\"") \ 
do { CODE; } while(0); \ 
_Pragma("clang diagnostic pop") \ 
}]; 

動作しますが、それはAPIユーザーにとって非常に見つけていないのです。

私が作ってみた最善の解決策は、ブロックの周り診断無効化を行い、このマクロですXCodeのエディタとのやりとりが悪いです。警告を無効にするか回避するためのより良い方法はありますか?

#pragma clang diagnostic push 
#pragma clang diagnostic ignored "<#A warning to ignore#>" 
<#Code that issues a warning#> 
#pragma clang diagnostic pop 

しかし、それは問題が修正されませんので、私は、この特定のケースでそれを使用することはありません。そこに#pragmaを使用してコードの特定の行に対する警告を無効にする簡単な方法があり、そもそも

+10

'self 'への' __weak'リファレンスを作成するには、文字通り1行のコードが必要です。私はこの場合の問題を解決することが症状を緩和しようとするよりも良いと思う。どのように 'self'の代わりに' weakSelf'を参照すると、ブロックの使い勝手が悪くなりますか? –

+3

それはカップルの方法でそれほど快適ではありません。リスナーは、しばしば非常に短く、時には単一のステートメントです。 __weak宣言は、リスナーのサイズを2倍にします。また、推論された自己を使用するのではなく、プロパティのアクセスを修飾する必要があることを意味します。私の現在の解決策はおそらく__weakを使用するよりも悪いことに同意するでしょうが、私はこの質問を通してより良い解決策を得ることを望んでいました。 –

+1

"self"引数を受け入れるように補完ブロックのプロトタイプを変更できますか?今度はブロックを渡すコードは同じように見えます(余分な引数を1つ受け入れることを除いて)、警告を取り除くことができます。 (すなわち、あなたのAPIが問題のオブジェクトをあなたのブロックに渡すようにしてください) – nielsbot

答えて

7

それは単にそれを開発者から隠すだけです。 私はむしろマークが提案した解決策をとることにします。弱参照を作成するには、ブロックの次の外側のいずれかを行うことができます

__weak typeof(self) weakSelf = self; // iOS ≥ 5 
__unsafe_unretained typeof(self) unsafeUnretainedSelf = self; // 5 > iOS ≥ 4 
__block typeof(self) blockSelf = self; // ARC disabled 
0

新しいLLVMは、そのようなものがios6とLLVMの出荷のためのサイクル 待機を保持するか、または作成してアレックスの方法を行う防止/検出に優れています弱いvar。

警告を無効にすることは悪い考えです。

1

私は警告を無効にすることは現在のところ、コンパイラには正しい唯一の方法だと思います。このサイクルを気にしないで、私はそれを認識しており、私は自分でオブザーバーを処分します。 弱参照は、実行時のCPUとメモリのオーバーヘッドがあるため、コストのかかるソリューションです。

0

私のような、私は、かなり賢いです...

#define CLANG_IGNORE_HELPER0(x) #x 
#define CLANG_IGNORE_HELPER1(x) CLANG_IGNORE_HELPER0(clang diagnostic ignored x) 
#define CLANG_IGNORE_HELPER2(y) CLANG_IGNORE_HELPER1(#y) 

#define CLANG_POP _Pragma("clang diagnostic pop") 
#define CLANG_IGNORE(x)\ 
    _Pragma("clang diagnostic push");\ 
    _Pragma(CLANG_IGNORE_HELPER2(x)) 

それはあなたが(Xcodeのあなた haranguingなし)楽しいことのすべてのソートを行うことができます考えている、次のマクロを書きました..

CLANG_IGNORE(-Warc-retain-cycles) 
[object performBlock:^(id obj){ [obj referToSelfWithoutWarning:self]; }]; 
CLANG_POP 

警告フラグを入れて、あなたの気まぐれに耳を傾けることができます。

CLANG_IGNORE(-Warc-performSelector-leaks); 
return [self performSelector:someIllBegotSelector withObject:arcFauxPas]; 
CLANG_POP 

はその後、再び、通常警告は理由があります。パーティーポッパー。

0

弱い参照を作成するという厄介な問題を解決するために、私はそれをマクロに入れます。これは、同じ名前ではなく接頭辞で新しいVARを作成するプリプロセッサを使用しています(この場合、「W」​​、;それは資本税制をより混乱やり過ぎとなるので、私は「弱い」回避):

#define WEAK_VAR(NAME) __unsafe_unretained typeof(NAME) w##NAME = NAME 

... 
WEAK_VAR(self); 
self.block = ^{ 
    [wself doStuff]; 
}; 

弱い参照が望ましくない場合は、使用しないでください。私はパラメータとしてオブジェクトを渡すnielsbotの解決が好きです(もちろん可能な場合)。