0

Can't receive JSON synchronously inside a block using AFNetworking. I checked this solution. It always nil at the end of method.

Here is my method:

- (BOOL)whois:(NSString *)domain withZone: (NSString*) zone
{        
    __block NSString *resultCode;

    NSURL *url = [[NSURL alloc] initWithString:@"myurl"];
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];

    AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {     
        resultCode = [JSON valueForKeyPath:[NSString stringWithFormat:@"%@.%@", domain,zone]];  //checked with NSLog, works well              
    } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
        NSLog(@"Request Failed with Error: %@, %@", error, error.userInfo);
    }];

    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    [queue addOperation: operation];
    [operation waitUntilFinished];

    if(resultCode == @"available") //nil here
    {
        return YES;
    }
    return NO; 
}
Community
  • 1
  • 1

2 Answers2

0

Instead of creating aNSOperationQueue, start your AFJSONRequestOperation with [operation start] and then call [operation waitUntilFinished] and it will block the main thread until it's finished. Then your resultCode should not be nil.

As @mattt said in the post you linked, it is strongly discouraged to freeze the thread like this. Consider figuring out another way to do this, such as calling a new method you hope to continue from your success block, and a different failure method from your failure block.

Irfan
  • 4,301
  • 6
  • 29
  • 46
Keith Smiley
  • 61,481
  • 12
  • 97
  • 110
0

Your method can't function with its current design.

- (BOOL)whois:(NSString *)domain withZone: (NSString*) zone
{        
    __block NSString *resultCode;

    NSURL *url = [[NSURL alloc] initWithString:@"myurl"];
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];

    // *** Runs 1st
    AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {     

        // *** runs 3rd
        resultCode = [JSON valueForKeyPath:[NSString stringWithFormat:@"%@.%@", domain,zone]];  //checked with NSLog, works well              
    } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
        NSLog(@"Request Failed with Error: %@, %@", error, error.userInfo);
    }];

    // *** Runs 2nd
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    [queue addOperation: operation];
    [operation waitUntilFinished];

    if(resultCode == @"available") //nil here
    {
        return YES;
    }
    return NO; 
}

Because the material in the block runs third, and asynchronously, you won't be able to return that value to the greater method in the manner it is currently designed. Perhaps use something like this:

- (void)whois:(NSString *)domain withZone: (NSString*) zone
{        

    NSURL *url = [[NSURL alloc] initWithString:@"myurl"];
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];

    __weak id weakSelf = self;
    // Runs 1st
    AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {     

        NSString *resultCode = [JSON valueForKeyPath:[NSString stringWithFormat:@"%@.%@", domain,zone]];  //checked with NSLog, works well       
        [weakSelf receivedResultCode:resultCode];       
    } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
        NSLog(@"Request Failed with Error: %@, %@", error, error.userInfo);
    }];
}

- (void) receivedResultCode:(NSString *)resultCode {
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    [queue addOperation: operation];
    [operation waitUntilFinished];

    if(resultCode == @"available") //nil here
    {
        // do @YES stuff
    }
    else {
        // do @NO stuff
    }
}

Obviously you'll have to change the design of whoever's calling it because it won't return a value in the way you specified. Perhaps there is a better solution, but I think this is the type of design required for it to work.

Logan
  • 52,262
  • 20
  • 99
  • 128