× {{alert.msg}} Never ask again
Get notified about new tutorials RECEIVE NEW TUTORIALS

Is it possible to pass completion blocks to a delegate parameter in Objective-C?

Julián Romero
Mar 12, 2015
<p>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.</p> <p>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. </p> <p>Super weird example ahead.</p> <p>For instance, in <code>UITableViewDataSource</code> delegate you have a method to obtain the number of rows in each section:</p> <pre><code>- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section </code></pre> <p>In order to use it you have to set the table <code>dataSource</code> property to some object that implements that method. The usual stuff.</p> <p>You can create a data source wrapper tha implement the original protocol and a new one you define to use your desired blocks interface.</p> <pre><code>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 &lt;UITableViewDataSource, RowsCounter&gt; { @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 </code></pre> <p>Then in your table controller:</p> <pre><code>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 &lt;#do your magic#&gt; return &lt;#rows#&gt;; }] </code></pre> <p>And the answer is still no, because you're using the original delegate...but under the hood your primary interface now is block based. </p> <p>This tip was originally posted on <a href="http://stackoverflow.com/questions/26327531/Is%20it%20possible%20to%20pass%20completion%20blocks%20to%20a%20delegate%20parameter%20in%20Objective-C?/26328371">Stack Overflow</a>.</p>
comments powered by Disqus