8

isFinishedインターフェイス ファイルに読み取り専用のプロパティがあります。

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

@interface TMSyncBase : NSObject {
     BOOL isFinished_;
}

@property (nonatomic, readonly) BOOL isFinished;

YESそして、保持サイクルを作成せずに、後である時点でブロックに設定したい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
}

これが正しい方法かどうかはわかりません。このコードは漏れたり壊れたりしますか? それとも問題ありませんか? おそらく私が見落としていたより簡単な方法がありますか?

4

2 に答える 2

6

渡すブロック変数はnilにすることができます。呼び出す前に確認するか、関数の開始時にassertを追加してください。そうしないと、クラッシュします。

自己を保持しておらず、コードが実行されるまでにバックグラウンドスレッドで長いタスクを実行すると想定しているため、weakSelfはnilになる可能性があります(ARCと5.0を使用しているため、弱参照を無効にしています)。

本当の弱参照がない場合(<5.0、ARCなし、コンパイラは__weakを受け入れますが、問題ではありません)、これはクラッシュにつながります。

また、「->」を使用してivarにアクセスすると、オブジェクトポインタがnilの場合にクラッシュが発生するため、発生しないようにする必要があります。

dasblinkenlightが書いたようにコードを実行しても、weakSelfが現時点でnilになるとクラッシュする可能性があります。たとえば、ブロックをバックグラウンドスレッドにディスパッチし、ブロックが実行される前にオブジェクトが解放されると、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);
};

また、weakSelfがnilであるかどうかをテストして、意味がない場合(オブジェクトが既に破棄されている場合)にコストのかかるタスクが実行されないようにすることもできます。ただし、これはユースケースによって異なります。

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

于 2012-07-04T10:40:22.223 に答える
1

わずかな回避策は、メソッドを作成し、コンパイラにそれを処理させることです。うまくいきますが、それが正しい方法かどうかはわかりません。誰かがそれが正しいかどうかを知ることができますか?

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

- (void)makeIsFinishedYes
{
    isFinished_ = YES;
}
于 2013-05-07T10:14:18.013 に答える