Ackman Ackman - 1 month ago 6
HTTP Question

AFNetworking returning null on first run

I have a list and when user clicks on one of the items on the list he is redirect to a different page based on the response of the HTTP request.

The code:

-(void) checkCardPresent{

// NSOperationQueue *networkQueue = [[NSOperationQueue alloc] init];
// networkQueue.maxConcurrentOperationCount = 5;
NSURL *url = [NSURL URLWithString:@"https://XXXXXXX/getCardDetails"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc]
initWithRequest:request];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
string = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
if([string isEqualToString:@""]){
self.isCardPresent = NO;
}
else{

self.isCardPresent = YES;
}
NSLog(@"%@", string);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"%s: AFHTTPRequestOperation error: %@", __FUNCTION__, error);
}];
//[networkQueue addOperation:operation];


Problem:
Now when I click on the item first I am taken to the wrong page. However on going back to the page again and clicking again I am taken to the right page.

More Data:
This code checks whether a user has an added payment method or not. On receiving blank text back he is taken to PAGE A.

On receiving a proper response with card data he is taken to page B.

Investigation:

The Code sample above on first click does NOT cause any operation and simply terminates (NO HTTP REQUEST). However, on second time click it returns the card details. i.e. executes the HTTP Request.

Does anyone know what is going on?

Answer

I think what's happening is that your navigation condition is running synchronously, but the condition being checked depends on state that is set asynchronously. That's speculation, but it's a common error and consistent with the wrong first-time behavior you're seeing.

Your navigation code currently probably looks something like this...

// on selection of an item
[self checkCardPresent];
if (self.isCardPresent) {
    // push to some vc
} else {
    // push to some other vc
}

But, isCardPresent is set well after the condition runs, once the network work is completed.

To fix, add a completion block to your network call, and use that block to do the navigation. Something like this...

// invoke completion with YES on success, no otherwise
- (void)checkCardPresentWithCompletion:(void (^)(BOOL))completion {
    NSURL *url = [NSURL URLWithString:@"https://XXXXXXX/getCardDetails"];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc]
                                         initWithRequest:request];
    [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
        string = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
        if([string isEqualToString:@""]){
            self.isCardPresent = NO;
        } else {
            self.isCardPresent = YES;
        }
        NSLog(@"%@", string);
        if (completion) completion(YES);

    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        NSLog(@"%s: AFHTTPRequestOperation error: %@", __FUNCTION__, error);
        if (completion) completion(NO);
    }];
}

Now, do your nav after the network request is complete...

// on selection of an item
// show some UI to indicate that we're busy
[self checkCardPresentWithCompletion:^(BOOL success) {
    // remove the UI that indicates we're busy
    if (success) {
        if (self.isCardPresent) {
            // push to some vc
        } else {
            // push to some other vc
        }
    } else {
        // show UI to indicate an error
    }
}];
Comments