Goal
I have a class with various properties that can be used to plug in a block to receive certain events.
@interface SomeClass
@property (copy, nonatomic) void (^handler)(int arg1, int arg2);
@end
In the client code, I would like to dynamically add / remove handler blocks to this property, similar to a MulticastDelegate in C#.
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.
}
};
For example, I would like to plug in logger
in -(id)init
, but only use doSomething
while a certain method is running. While doSomething
is plugged in, logger
should still run.
Current implementation
To maintain the blocks, I thought about using an NSMutableArray
that stores copies of the blocks and broadcasts the event to all registered blocks (observer pattern).
- (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];
Open questions
Can the method be generalized to blocks with any argument count / types? So that I could use it like this:
MulticastBlock *b = [[MulticastBlock alloc] init];
self.object.handler = b;
[b addBlock:self.logger];
The problem here is that the type of self.object.handler
is void (^)(int, int)
. Therefore, MulticastBlock
would need to mimic a block, forwarding any invocations it receives to the array.
Could the techniques described here by used?
Maybe intercepting all invocations, copying them for every array element and assigning new invocation targets?