Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to pass methods as blocks?

I hate blocks. They are meant to make the code more concise, but I couldn't find anything more ugly. For instance, with AFNetworking:

AFJSONRequestOperation* operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request
             requestsuccess:^(NSURLRequest *request, NSURLResponse *response, id JSON) {
  // Some
  // very
  // long
  // (and as ugly as blocks)
  // processing
}
                    failure:^(NSURLRequest *request, NSURLResponse *response, NSError *error, id JSON )) {
  // Failure code
}]

Something like this would have been much better:

AFJSONRequestOperation* operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request
             requestsuccess:@selector(requestSuccess:response:json:)
                    failure:@selector(requestSuccess:response:error:)]

So, is it possible to use method's selectors as blocks ? If not, how can I make the block code better ?

It annoys me, as these blocks seems to be the future of objective-c programming and they are just NOT readable.

like image 924
ldiqual Avatar asked Jul 05 '12 19:07

ldiqual


2 Answers

So you think the block construct makes the code harder to read? I think they can sometimes make things easier to understand, especially in asynchronous contexts like in networking code.

To make it easier to read you can assign blocks to variables. (Indeed blocks are objective-c objects.)

Example:

typedef void(^SuccessBlock)(NSURLRequest *request, NSURLResponse *response, id JSON);

SuccessBlock successBlock = ^(NSURLRequest *request, NSURLResponse *response, id JSON) {
    // code block
};

AFJSONRequestOperation* operation;
operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request
                                                            success:successBlock
                                                            failure:nil];

You can also call a single handler method inside the block to keep it small.

like image 52
Felix Avatar answered Nov 04 '22 10:11

Felix


Short blocks are good, overly long ones not, where you draw the line is of course a personal preference...

Using a method for a block is not hard (the other way around is more of a challenge). The simplest approach if you wish to use a method:

- (void) requestSuccess:(NSURLRequest *)request
               response:(NSURLResponse *)response
                   json:(id)JSON
{
   // Some
   // very
   // long
   // (and as ugly as blocks)
   // processing
}

- (void) requestFailure:(NSURLRequest *)request
               response:(NSURLResponse *)response
                  error:(NSError **)error
                   json:(id)JSON
{
   // Failure code
}

...

AFJSONRequestOperation* operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request
         requestsuccess:^(NSURLRequest *request, NSURLResponse *response, id JSON)
         {
            [self requestSuccess:request response:response json:JSON];
         }
         failure:^(NSURLRequest *request, NSURLResponse *response, NSError *error, id JSON ))
         {
            [self requestFailure:request response:response error:error json:JSON];
         }]

You could go further with macros, or even performSelector/NSInvocation fun - whether it is worth it is up to you.

You can also move the blocks definitions before the call itself, along the lines of:

var = block;
[object method:var];

Which approach you choose is a matter of style.

like image 30
CRD Avatar answered Nov 04 '22 11:11

CRD