iOS - Passing blocks to functions

2020-07-22 09:54发布

问题:

I have a method call (it's a call from AFNetworking):

AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON)
                                     {
                                         NSLog(@"IP Address: %@", [JSON valueForKeyPath:@"origin"]);

                                     } failure:^(NSURLRequest *request , NSURLResponse *response , NSError *error , id JSON)
                                     {
                                         NSLog(@"Failed: %@",[error localizedDescription]);
                                     }];

and I'm trying to pull the sucess and failure blocks out into a separate variable, that I can later pass into the method. But I can't figure out how to declare the blocks as variables. I'm looking to do something like this:

IDontKnowWhatKindOfDataTypeGoesHere successBlock = ^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON)
{
  NSLog(@"IP Address: %@", [JSON valueForKeyPath:@"origin"]);  
}

and the same for the failureBlock.

So then I'm looking to make the AFJSONRequestOperation call like:

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

But I cant figure how what the data types of the successBlock and failureBlock should be.

This is more for organization I suppose. I have a lot of code in my successBlock and the autoformatting of Xcode pushes is all to the right side of the screen which is totally annoying. So if I can pull it out (which should be possible, right), then I can organize my code better.

Thanks!

回答1:

It's awkward until you get used to it. The variable name appears mixed in with the type...

void (^success)(NSURLRequest *, NSHTTPURLResponse *, id) = ^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
   NSLog(@"request is %@, response is %@ and json is %@", request, response, JSON);
};

The stack variable name in this case is success. You can now refer to it in subsequent expressions that take the same type, like ...

AFJSONRequestOperation *operation = [AFJSONRequestOperationJSONRequestOperationWithRequest:request
                                        success:success];

You can also make a block an property, like this:

@property (copy, nonatomic) void (^success)(NSURLRequest *, NSHTTPURLResponse *, id);

And call it like this:

self.success(aRequest, aResponse, someJSON);

Remember to nil it out when you're done calling it, so the caller has less to worry about creating a retain cycle.

Edit: good suggestion in commentary about using typedef to make this easier on the eyes and fingers:

typedef void (^SuccesBlock)(NSURLRequest *, NSHTTPURLResponse *, id);

So the stack variable looks like this:

SuccessBlock success = ^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
   NSLog(@"request is %@, response is %@ and json is %@", request, response, JSON);
};

and the property looks like this:

@property (copy, nonatomic) SuccessBlock success;