目标
我有一个具有各种属性的类,可以用来插入一个块来接收某些事件。
@interface SomeClass
@property (copy, nonatomic) void (^handler)(int arg1, int arg2);
@end
在客户端代码中,我想动态添加/删除处理程序块到此属性,类似于C#中的MulticastDelegate。
self.logger = ^(int arg1, int arg2){
NSLog(@"arg1 = %d, arg2 = %d", arg1, arg2);
};
void (^doSomething)(int, int) = ^(int arg1, int arg2){
if (arg1 == 42) {
// Do something.
}
};
例如,我想在logger
中插入-(id)init
,但在某个方法运行时仅使用doSomething
。插入doSomething
后,logger
仍应运行。
当前实施
为了维护块,我考虑使用存储块副本的NSMutableArray
并将事件广播到所有已注册的块(观察者模式)。
- (id)init
self.handlerBlocks = [NSMutableArray array];
__weak typeof(self) weakSelf = self;
self.object.handler = ^(int x, int y){
typeof(self) strongSelf = weakSelf;
if (!strongSelf) {
return;
}
for (void (^item)(int x, int y) in strongSelf.handlerBlocks) {
item(x, y);
}
};
[self.handlerBlocks addObject:[self.logger copy]];
- (void)someOtherMethod
void (^doSomething)(int, int) = [^(int arg1, int arg2){
if (arg1 == 42) {
// Do something.
}
} copy];
[self.handlerBlocks addObject:doSomething copy];
// Do something.
[self.handlerBlocks removeObject:doSomething];
打开问题
可以将该方法推广到具有任何参数计数/类型的块吗?所以我可以像这样使用它:
MulticastBlock *b = [[MulticastBlock alloc] init];
self.object.handler = b;
[b addBlock:self.logger];
此处的问题是self.object.handler
的类型为void (^)(int, int)
。因此,MulticastBlock
需要模仿一个块,将它收到的任何调用转发给数组。
这里介绍的技术可以用吗?
可能拦截所有调用,为每个数组元素复制它们并分配新的调用目标?
答案 0 :(得分:1)
从您提供给mikeash.com的链接中,您会看到在代码中执行此操作是一项挑战,而不是要包含在生产代码中。出于类似的原因,C#stuff的工作原理是因为它是由运行时提供的,所以你不能轻易地在C#中编写它。即使是参数多态也不会对你有帮助,它不会让你使用不同数量的参数进行块调用。
你需要的是通过字符串扩展的“参数多态”...即宏。
以下是“MulticastBlock.h”文件示例:
#define MULTICAST(name, typelist, arglist) \
\
@interface name : NSObject \
\
@property (readonly) void (^block)typelist; \
\
- (id) addBlock:(void (^)typelist)aBlock; \
\
- (void) removeBlock:(id)token; \
\
@end
MULTICAST(MulticastBlock, (int arg1, int arg2), (arg1, arg2))
MULTICAST(MulticastBlock2, (NSString *arg1, NSString *arg2), (arg1, arg2))
#undef MULTICAST
这定义了一个宏,它扩展为@interface
,使用它两次,然后删除不再需要的宏。
实现遵循您的代码,并且同样使用宏 - 它在循环中使用arglist
宏参数进行调用,我只是在此处包含它以保持一致性,尽管它没有被使用。
我对您的代码进行的唯一重大更改是使用带有自动生成密钥的NSMutableDictionary
(只是一个递增的数字) - 密钥由addBlock:
返回并由{{1}接受并且避免了复制块的任何问题(如果它们是相同的块,则两个块只相等)
不完全是你想要的但它有效。
<强>附录强>
好的,目前还不清楚如何使用它,这是我的测试代码,应该解释所有:
removeBlock: