ldiqual
ldiqual

Reputation: 15365

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.

Upvotes: 11

Views: 5451

Answers (3)

CRD
CRD

Reputation: 53000

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.

Upvotes: 2

Felix
Felix

Reputation: 35384

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.

Upvotes: 7

MechEthan
MechEthan

Reputation: 5703

You can peel out the blocks so they're not in-line parameters to method calls. It still involves a bit of block ugliness, but still improves readability some:

void (^successBlock)(NSURLRequest *request, NSHTTPURLResponse *response, id JSON);

successBlock = ^ (NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
  // Some
  // very
  // long
  // (and as ugly as blocks)
  // processing
};
//do same for failure block as "failureBlock"
...

AFJSONRequestOperation* operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request
             requestsuccess:successBlock
                    failure:failureBlock];

Upvotes: 1

Related Questions