デリゲートオブジェクトを取得するように設計された既存のクラスと通信したいようです。次のような多くのアプローチがあります。
- カテゴリを使用して、適切なメソッドのブロックベースのバリアントを追加します。
- 派生クラスを使用して、ブロックベースのバリアントを追加します。と
- プロトコルを実装し、ブロックを呼び出すクラスを作成します。
これが(3)を行う1つの方法です。まず、SomeObjectが次のようになっていると仮定します。
@protocol SomeObjectDelegate
@required
- (void)stuffDone:(id)anObject;
- (void)stuffFailed;
@end
@interface SomeObject : NSObject
{
}
+ (void) testCallback:(id<SomeObjectDelegate>)delegate;
@end
@implementation SomeObject
+ (void) testCallback:(id<SomeObjectDelegate>)delegate
{
[delegate stuffDone:[NSNumber numberWithInt:42]];
[delegate stuffFailed];
}
@end
したがって、テストする方法がいくつかあります。実際のSomeObjectがあります。
次に、プロトコルを実装し、提供されたブロックを呼び出すクラスを定義します。
#import "SomeObject.h"
typedef void (^StuffDoneBlock)(id anObject);
typedef void (^StuffFailedBlock)();
@interface SomeObjectBlockDelegate : NSObject<SomeObjectDelegate>
{
StuffDoneBlock stuffDoneCallback;
StuffFailedBlock stuffFailedCallback;
}
- (id) initWithOnDone:(StuffDoneBlock)done andOnFail:(StuffFailedBlock)fail;
- (void)dealloc;
+ (SomeObjectBlockDelegate *) someObjectBlockDelegateWithOnDone:(StuffDoneBlock)done andOnFail:(StuffFailedBlock)fail;
// protocol
- (void)stuffDone:(id)anObject;
- (void)stuffFailed;
@end
このクラスは、渡したブロックを保存し、プロトコルコールバックに応答してそれらを呼び出します。実装は簡単です。
@implementation SomeObjectBlockDelegate
- (id) initWithOnDone:(StuffDoneBlock)done andOnFail:(StuffFailedBlock)fail
{
if (self = [super init])
{
// copy blocks onto heap
stuffDoneCallback = Block_copy(done);
stuffFailedCallback = Block_copy(fail);
}
return self;
}
- (void)dealloc
{
Block_release(stuffDoneCallback);
Block_release(stuffFailedCallback);
[super dealloc];
}
+ (SomeObjectBlockDelegate *) someObjectBlockDelegateWithOnDone:(StuffDoneBlock)done andOnFail:(StuffFailedBlock)fail
{
return (SomeObjectBlockDelegate *)[[[SomeObjectBlockDelegate alloc] initWithOnDone:done andOnFail:fail] autorelease];
}
// protocol
- (void)stuffDone:(id)anObject
{
stuffDoneCallback(anObject);
}
- (void)stuffFailed
{
stuffFailedCallback();
}
@end
覚えておく必要があるのは、初期化時にブロックをBlock_copy()し、後でBlock_release()することだけです。これは、ブロックがスタックに割り当てられ、オブジェクトが作成中のスタックフレームよりも長持ちする可能性があるためです。Block_copy()は、ヒープ内にコピーを作成します。
これで、すべてのデリゲートベースのメソッドがブロックを渡すことができます。
[SomeObject testCallback:[SomeObjectBlockDelegate
someObjectBlockDelegateWithOnDone:^(id anObject) { NSLog(@"Done: %@", anObject); }
andOnFail:^{ NSLog(@"Failed"); }
]
];
この手法を使用して、任意のプロトコルのブロックをラップできます。
ARC補遺
コメントへの応答:このARCと互換性を持たせるには、Block_copy()
直接割り当てを残すための呼び出しを削除するだけです。
stuffDoneCallback = done;
stuffFailedCallback = fail;
メソッドを削除しdealloc
ます。Blockcopy
に変更することもできますcopy
。つまりstuffDoneCallback = [done copy];
、これは、ARCのドキュメントを読むことで必要になると思われるものです。ただし、割り当てが強力な変数に割り当てられているため、ARCは割り当てられた値を保持し、スタックブロックを保持するとヒープにコピーされます。したがって、生成されたARCコードは、の有無にかかわらず同じ結果を生成しcopy
ます。