6

私は私のインターフェイスファイルに読み取り専用プロパティisFinishedを持っている:割り当て

typedef void (^MyFinishedBlock)(BOOL success, NSError *e); 

@interface TMSyncBase : NSObject { 
    BOOL isFinished_; 
} 

@property (nonatomic, readonly) BOOL isFinished; 

と私は作成せず、後のある時点でブロックにYESにそれを設定したいですA selfにサイクルを保持:

- (void)doSomethingWithFinishedBlock:(MyFinishedBlock)theFinishedBlock { 
    __weak MyClass *weakSelf = self; 
    MyFinishedBlock finishedBlockWrapper = ^(BOOL success, NSError *e) { 
     [weakSelf willChangeValueForKey:@"isFinished"]; 
     weakSelf -> isFinished_ = YES; 
     [weakSelf didChangeValueForKey:@"isFinished"]; 
     theFinishedBlock(success, e); 
    }; 

    self.finishedBlock = finishedBlockWrapper; // finishedBlock is a class ext. property 
} 

私は、これはそれを行うための正しい方法であることをわかりませんよ。このコードが漏洩するか、中断するか、それとも問題ありませんか?おそらく私は見落とした方が簡単でしょうか?

+2

ちょうどちなみに、あなたは '__weak typeof演算(自己)* weakSelf =自己を使用することができます;' –

+0

は涼しく、それは便利です! – manmal

+4

一般的な宣言である '__weak typeof(self)weakSelf = self;に対する小さな修正' typeof(self)はすでにポインタです。 – allprog

答えて

5

ブロック変数を渡すと、nilに呼び出す前に確認したり、機能の起動時にアサートを追加したり、自己を保持していないと我々はあなたがバックグラウンドスレッドでいくつかの長いタスクを実行することを前提としていますので、あなたが

をクラッシュすることができますあなたのコードが実行されるまでの時間weakSelfはゼロにすることができます(うまくいけば、あなたはARCと5.0を使用しているので、弱い参照を埋め込むことができます)。

実際の弱い参照(< 5.0、ARCなし、コンパイラはまだ__weakを受け入れますが、それは問題ではありません)を持っていないと、クラッシュする可能性があります。

また、 ' - >'を使ってivarにアクセスすると、オブジェクトポインタがnilの場合にクラッシュするので、起こらないようにする必要があります。

dasblinkenlightがweakSelfは、現時点ではnilになる場合、それがクラッシュする可能性が書いたように、あなたがコードを実行する場合でも、あなたがバックグラウンドスレッドでブロックを派遣して、ブロックの実行前にリリース取得するには、オブジェクトとしましょう、これはこのようにそれをaccesing nilをweakSelfを作ります' - >'を使用するとクラッシュする可能性があります。次のようにその場合、私は、コードを変更します:weakSelfは、実行から、高価なタスクを防ぐためにnilの場合

__weak MyClass *weakSelf = self; 
MyFinishedBlock finishedBlockWrapper = ^(BOOL success, NSError *e) { 
    MyClass *strongSelf = weakSelf; 
    //! whatever task you want executed 
    strongSelf.isFinished = YES; 
    theFinishedBlock(success, e); 
}; 

はまた、あなたがテストすることができ、それは意味がない場合(オブジェクトがすでに破棄されます)。しかし、これはユースケースに依存します。

ブロックを使用してプログラミングするときに考慮する必要がある場合もあります。 バックグラウンドでタスクを実行するロールのみのジョブオブジェクトインスタンスを使用できます。この場合、このコードは失敗する可能性があります新しいタスクを作成し、バックグラウンドスレッドでブロックが実行される前に割り当てを解除することができます。その場合、オブジェクトを保持してオブジェクト内にブロックを保持しないでください(これにより保持サイクルが防止されます)。

+0

ありがとう!はい、それはiOS5です、よろしくお願いします。 – manmal

+0

isFinishedは読み取り専用のプロパティなので、 '' 'strongSelf.isFinished = YES'''を動作させたくありません。KVO用です。 – manmal

+1

プライベートカテゴリの通常の割り当てを指定すると、isFinished書き込み可能になりますあなたのクラスコードで読んでいるだけではなく、これは不要な手動KVO通知もスキップします。 –

0

ちょっとした回避策は、メソッドを作成してコンパイラで処理する方法です。うまく動作しますが、正しい方法であるかどうかはわかりません。誰かが正しいかどうかを伝えることはできますか?

__weak MyClass *weakSelf = self; 
MyFinishedBlock finishedBlockWrapper = ^(BOOL success, NSError *e) { 
    [weakSelf makeIsFinishedYes]; 
}; 

- (void)makeIsFinishedYes 
{ 
    isFinished_ = YES; 
}