0

NSNotificationCenter'sと同様の動作を実装したい-addObserverForName:object:queue:usingBlock:。次のようなメソッドを使用する

- (void)addRefetchObserver:(id)observer
                   handler:(FJRefetchHandler)handler;

ブロックは、後で呼び出すために保存する必要があります(FJRefetchHandler次のように定義されます:typedef void(^FJRefetchHandler)(void)

後でブロックを削除したいのでobserver、次のメソッドも保存して宣言します。

- (void)removeRefetchObserver:(id)observer;

使用法は次のようになります。

// some place in code
[controller addRefetchObserver:self handler:^{
    // refetch some stuff, i.e.
    self.data = [self updateData];
}];    
// some other place in code:
[controller removeRefetchObserver:self];

私の質問は-addRefetchObserver:handler:、保持サイクルを作成しないようにどのように実装する必要があるかということです。オブザーバーとハンドラーをどのように保存する必要がありますか?

どうやら、NSNotificationCenterオブザーバーを保持せずに保存しているようです。そうしないと、呼び出さ[center removeObserver:self]れないため、呼び出す-deallocことができ-deallocません。

また、ブロック内で__unsafe_unretained参照するときに使用を回避する方法はありますか?selfつまり、そのように:

__unsafe_unretained MyObject *blockSelf = self;
[controller addRefetchObserver:self handler:^{
    blockSelf.data = [blockSelf updateData];
}];
4

2 に答える 2

1

どうやら、 NSNotificationCenter は何らかの方法でオブザーバーを保持せずに保存します。そうしないと、 -dealloc で [center removeObserver:self] を呼び出すことができません。

はい、彼らはそれへの弱い参照を保持しています。クラス内のオブザーバーへの弱参照も簡単に保持できます。弱参照のコレクションが必要な場合は、Core Foundation 関数を使用して CFArray / CFSet / を作成し、保持しないバージョンの NSArray または NSSet または NSDictionary を作成できます。 CFDictionary (それらは、保持/解放動作を明示的に指定できるようにする、つまり、NS の同等物と同じで、無料でブリッジされます)。強い参照を持たないようにするには、保持と解放で何もしないようにします。

オブザーバーを保存しているのはちょっと奇妙です。NSNotificationCenter では、呼び出しを行うためにオブザーバーとセレクターの両方が必要なため、オブザーバーを保存します。あなたのものでは、ブロックはすでに呼び出しを行うのに十分であり、ブロックはオブザーバーを使用するすべてのロジックをカプセル化しているため、「オブザーバー」を個別に保存するのは奇妙に思えます。あなたがそれを持っている唯一の理由は、それを取り除く方法があるようです. さらに言えば、削除する場合と追加する場合に同じオブジェクトを渡す限り、それは任意のオブジェクトである可能性があります。

NSNotificationCenter には「オブザーバー」への参照が 1 つしかありませんが、システムには 2 つの参照があります。1 つは「オブザーバー」として渡されますが、ブロックへの参照もあり、おそらく「オブザーバー」への参照があります。また。NSNotificationCenter と同じように機能させたい場合は、これらが両方とも弱参照であることを確認する必要があります。私はあなたがこれを理解したと思います-最初の段落で説明したことを使用して、あなたが弱いままにしている直接の「オブザーバー」参照。「オブザーバー」へのブロックの参照も弱い必要があります。

また、ブロック内で自己を参照するときに __unsafe_unretained を使用して回避する方法はありますか? つまり、次のようになります。

あなたが持っているのは、ブロックから何かを弱参照する正しい方法です。より具体的には、__weakARC を使用していて、iOS 5 以降のみをターゲットにしている場合に使用する必要があります。__unsafe_unretainedARCを使用している場合は、(持っているように)使用する必要があります。__blockARC を使用していない場合は、使用する必要があります。

于 2012-11-22T23:27:00.840 に答える
1

ブロック内で self を呼び出すより良い方法は、self の参照を同じ弱い変数にコピーし、それをブロック内で使用することです。

MyController __weak *__weakController = controller;
[__weakController addRefetchObserver:self handler:^{
    // refetch some stuff, i.e.
    __weakController.data = [__weakController updateData];
}];    
// some other place in code:
[controller removeRefetchObserver:self];

ただし、長時間の継続的な操作を扱っている場合があり、その間、ブロックがまだ進行中にコントローラーが解放されることがあります。ブロックはスタックに配置され、実行を続けるため、次のようにいくつかのメソッドを呼び出す前に、コントローラーがまだ存在するかどうかを確認することをお勧めします。

 MyController __weak *__weakController = controller;
    [__weakController addRefetchObserver:self handler:^{
         // some long on going tasks ...
        MyController __strong *strongController = __weakController;
        if(strongController)
          strongController.data = [strongController updateData];
    }];    
    // some other place in code:
    [controller removeRefetchObserver:self];
于 2012-11-21T22:18:30.753 に答える