听起来您希望与旨在获取委托对象的现有类进行通信。有多种方法,包括:
- 使用类别添加适当方法的基于块的变体;
- 使用派生类添加基于块的变体;和
- 编写一个实现协议并调用您的块的类。
这是执行 (3) 的一种方法。首先我们假设您的 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
to copy
, i.e. stuffDoneCallback = [done copy];
,这就是您在阅读 ARC 文档后可能会认为需要的内容。然而,这并不是因为对强变量的赋值会导致 ARC 保留分配的值 - 并保留堆栈块将其复制到堆。因此,生成的 ARC 代码无论有无copy
.