1

Or does the method have to be written to accept a block? Put another way, if we don't control the code that defines the method, are we at the mercy of using delegates if that's how it's defined, or is there a way to pass two anonymous functions (blocks) within a method call that is expecting a delegate?

RedWoolven
  • 43
  • 6
  • Can you give an actual example? What's your use case where you need to know this? – matt Oct 12 '14 at 17:26
  • You might be interested in reading [Creating delegates on the spot with blocks](http://stackoverflow.com/q/15438410). – jscs Oct 12 '14 at 18:36

3 Answers3

6

Technically the answer is no, if some library or class works with delegates there is probably a good reason and the smart and easier thing to do is use them.

If for some reason you're really interested in using blocks because it's more natural for your problem domain you can implement a wrapper.

Super weird example ahead.

For instance, in UITableViewDataSource delegate you have a method to obtain the number of rows in each section:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section

In order to use it you have to set the table dataSource property to some object that implements that method. The usual stuff.

You can create a data source wrapper tha implement the original protocol and a new one you define to use your desired blocks interface.

typedef NSUInteger (^RowsCounterBlock)(NSInteger section);

@protocol RowsCounter
- (void)tableViewController:(id)controller countRowsWithBlock:(RowsCounterBlock)block;
@end

// we implement both the original protocol and our block based protocol
@interface ComplexDataSource : NSObject <UITableViewDataSource, RowsCounter>
{
    @property(strong) RowsCounterBlock counterBlock;
}

// save a block that knows how to count rows
- (void)tableViewController:(id)controller countRowsWithBlock:(RowsCounterBlock)block
{
    controller.dataSource = self;
    self.counterBlock = block;
}

// use the saved block to implement the method defined in the original delegate
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    if (!self.counterBlock) return 0;
    return self.counterBlock(section);
}

@end

Then in your table controller:

self.source = [ComplexDataSource new]; // save the data source in a property
[self.source tableViewController:self
              countRowsWithBlock:^NSUInteger(NSInteger section) {
              // this will be called each time the table view needs to ask
              // for the number of rows via the proxy delegate
              <#do your magic#>
              return <#rows#>;
}]

And the answer is still no, because you're using the original delegate...but under the hood your primary interface now is block based.

djromero
  • 19,551
  • 4
  • 71
  • 68
1

Short question is no, if the method is defined to get a delegate parameter, you're out of luck if you want to use a block.

But, as the other people said, sometimes a delegate pattern is better than a block, it all comes down to the use cases. Maybe if the API designer chose a delegate instead of a block, there is a reason.

IMHO blocks are most useful when it comes to success or failure callbacks, but in a lot of other cases a delegate is still better (though, I would also love to use an anonymous class, Java-style :) but that's just because sometimes we're lazy)

Vik
  • 1,897
  • 12
  • 18
0

First of all, delegation is in many cases better than using a closure. In other cases closures are better. So at the very beginning one should ask: Why?

However: What is the problem to define a delegate method that calls a closure?

Amin Negm-Awad
  • 16,582
  • 3
  • 35
  • 50