Why can't I return an object from my block?

2019-01-20 05:55发布

问题:

I'm trying to return a NSMutableArray from my block in my method, but when I add the line return [responseString JSONValue];, I get some compiler warnings.

- (NSMutableArray*)getTodayData:(NSDate*)today
{
        ASIFormDataRequest *request = [[[ASIFormDataRequest alloc] initWithURL:url] autorelease];
        [request setPostValue:[dateFormat stringFromDate:today] forKey:@"target_date"];
        NSError *error = [request error];

        [request setCompletionBlock:^{
            NSString *responseString;
            if (!error) {
                responseString = [request responseString];
                return [responseString JSONValue];
            } else {
                NSLog(@"error: %@", error);
            }
        }];
        [request setFailedBlock:^{
            NSString *responseString;
            if (!error) {
                responseString = [request responseString];
            } else {
                NSLog(@"error: %@", error);
            }
        }];
        [request startAsynchronous];
}

回答1:

The setCompletionBlock: and setFailedBlock: methods in ASIFormDataRequest do not accept blocks with a return value. You need to restructure your code so that there is no return value.

For example:

- (void)viewDidLoad
{
  [self getTodayData:self.datePicker.date];
}

- (void)getTodayData:(NSDate*)today
{
      self.appointmentsArray = [NSArray array]; // set it to an empty value now, so the table view displays nothing

      ASIFormDataRequest *request = [[[ASIFormDataRequest alloc] initWithURL:url] autorelease];
      [request setPostValue:[dateFormat stringFromDate:today] forKey:@"target_date"];
      NSError *error = [request error];

      [request setCompletionBlock:^{
          NSString *responseString;
          if (!error) {
              responseString = [request responseString];
              self.appointmentsArray = [responseString JSONValue];

              [self.appointmentsArrayTableView reloadData]; // I'm assuming you want to display the appointments in some view
          } else {
              NSLog(@"error: %@", error);
          }
      }];
      [request setFailedBlock:^{
          NSString *responseString;
          if (!error) {
              responseString = [request responseString];
          } else {
              NSLog(@"error: %@", error);
          }
      }];
      [request startAsynchronous];
}


回答2:

What are you expecting returning an object to do? Presumably the completion block that you hand to ASIFormDataRequest is declared as void (^)() (or dispatch_block or some other typedef which evaluates to void (^)()). Given this, the code calling the block isn't expecting a return value. It would be like implementing a method declared - (void)foo and trying to return an object from that; it just doesn't make sense.

Edit: After re-reading your code, I expect what you're really trying to do is returning a value from -getTodayData:. However you're executing an asynchronous request. The method -getTodayData: has already returned long before your block is executed.



回答3:

The block is defined as void. Think about how you are trying to interact with the block. What are you trying to return from the block? Who would it return to? How?

I think one misunderstanding you are having is dealing with asynchronous programming. Your method - (NSMutableArray*)getTodayData:(NSDate*)today is actually only sending a request. It is not returning an array. You send the request, and the request will execute the block once it is completed. But your program will have already returned from your getTodayData: method by the time the block gets executed. It will have no return value.

What you want to do instead is to use a delegate. When the block is executed at the completion of the request, you can notify the delegate that the response is now stored somewhere—preferably as an instance variable—and is now ready to be accessed.