AFNetworking Array returns JSON inside of block but not outside of block [duplicate]

≡放荡痞女 提交于 2019-12-11 12:06:28

问题


I've created a custom method that returns JSON data using the AFNetworking API.

I'm trying to store data pulled from my web service in an Array as JSON. NSLog(@"%@", json); inside the block prints the JSON data to console. Outside the block NSLog(@"%@", json); return null. Why is this and how can it be fixed?

What I'm trying to do is to get the method to return the JSON data (NSArray)

#import "WebService.h"
#import "AFNetworking.h"
#import "MBProgressHUD.h"

@implementation WebService

- (NSArray *)postRequest:(NSDictionary *)postParameters {

//MBProgressHUD *progressHUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
//progressHUD.labelText = @"Loading";

__block NSArray *json;

AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager POST:@"http://192.168.0.100/app.php" parameters:postParameters success:^(AFHTTPRequestOperation *operation, id responseObject)
 {
     NSString *responseString = [operation responseString];

     NSError *error;

     json = [NSJSONSerialization
                      JSONObjectWithData:[responseString dataUsingEncoding:NSUTF8StringEncoding]
                      options:kNilOptions
                      error:&error];

     NSLog(@"%@", json); // RETURNS JSON

 } failure:^(AFHTTPRequestOperation *operation, NSError *error) {

     UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Network Unavailable"
                                                     message:@"Unable to contact server. Please try again later."
                                                    delegate:nil
                                           cancelButtonTitle:@"OK"
                                           otherButtonTitles:nil];
     [alert show];

     NSLog(@"Error: %@", error);

 }];

     NSLog(@"%@", json); // RETURNS NULL

     return json;
}

@end

回答1:


The POST method is asynchronous. Meaning that that block goes to a separate thread and waits to execute. While that is going to the background the rest of your code continues on as though nothing happened. So it gets immediately to the NSLog statement(probably before even starting you POST request).

If you want the json object outside of your block you are going to have to dispatch from inside the block to a method of your choosing and continue your operations there.

[manager POST:@"http://192.168.0.100/app.php" parameters:postParameters success:^(AFHTTPRequestOperation *operation, id responseObject)
 {
     NSString *responseString = [operation responseString];

     NSError *error;

     json = [NSJSONSerialization
                      JSONObjectWithData:[responseString dataUsingEncoding:NSUTF8StringEncoding]
                      options:kNilOptions
                      error:&error];

     NSLog(@"%@", json); // RETURNS JSON
     dispatch_async(dispatch_get_main_queue(), ^{
          [self doSomethingWithJson:json];
     });

 } failure:^(AFHTTPRequestOperation *operation, NSError *error) {

     UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Network Unavailable"
                                                     message:@"Unable to contact server. Please try again later."
                                                    delegate:nil
                                           cancelButtonTitle:@"OK"
                                           otherButtonTitles:nil];
     [alert show];

     NSLog(@"Error: %@", error);

 }];



回答2:


Because POST runs asynchronously, it's not possible to return the results. But you can employ the same completion block pattern that AFNetworking does:

- (void) postRequest:(NSDictionary *)postParameters success:(void (^)(id jsonObject))success failure:(void (^)(NSError *error))failure {

    AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
    [manager POST:@"http://192.168.0.100/app.php" parameters:postParameters success:^(AFHTTPRequestOperation *operation, id responseObject)
     {
         if (success)
             success(responseObject);
     } failure:^(AFHTTPRequestOperation *operation, NSError *error) {

         UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Network Unavailable"
                                                         message:@"Unable to contact server. Please try again later."
                                                        delegate:nil
                                               cancelButtonTitle:@"OK"
                                               otherButtonTitles:nil];
         [alert show];

         if (failure)
             failure(error);        
     }];
}

And you call that as:

[self postRequest:postParameters success:^(id jsonObject) {
    NSLog(@"json = %@", jsonObject);
} failure:^(NSError *error) {
    NSLog(@"error = %@", error);
}];

Note, I've simplified your code significantly, because you don't have to do the JSON parsing, because AFNetworking already does that for you (because the default responseSerializer is AFJSONResponseSerializer). So as you can see, your above method doesn't do much more than the standard AFNetworking POST method which shows a UIAlertView if there was an error.




回答3:


In addition to wat @Putz1103 says, you could use callback methods, this is a technique also used in JavaScript.

Example:

[manager POST:@"http://192.168.0.100/app.php" parameters:postParameters success:^(AFHTTPRequestOperation *operation, id responseObject)
 {
     NSString *responseString = [operation responseString];

     NSError *error;

     json = [NSJSONSerialization
                      JSONObjectWithData:[responseString dataUsingEncoding:NSUTF8StringEncoding]
                      options:kNilOptions
                      error:&error];

     NSLog(@"%@", json); // RETURNS JSON
     [self dataRetrievedWithData:json];

 } failure:^(AFHTTPRequestOperation *operation, NSError *error) {

     UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Network Unavailable"
                                                     message:@"Unable to contact server. Please try again later."
                                                    delegate:nil
                                           cancelButtonTitle:@"OK"
                                           otherButtonTitles:nil];
     [alert show];

     NSLog(@"Error: %@", error);

 }];

Then you would have a method like:

- (void)dataRetrievedWithData:(id)data
{
  NSLog(@"Here's the data.. do what you want to do with the data here. %@", data);
}

In that last method you can add logic to execute when the request is completed successfully. Returning from the block is not really feasible since the block is executed on a separate thread.

The operation is asynchronous which means you can simply print out the response after it arrives. Asynchronous means it runs in a separate thread so you have to wait for the response prior to being able to do anything with the response.



来源:https://stackoverflow.com/questions/21739790/afnetworking-array-returns-json-inside-of-block-but-not-outside-of-block

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!