Search code examples
iosobjective-cobjective-c-blocksscoping

Blocks, scoping and setting variables Objective C


I am using AFNetworking AFHTTPSessionManager to make a GET request. When I log the response object, the responseObject is logged. When I try to log my locationIDsDictionary, I get null. Scoping issue? Does locationIDsDictionary need to be a _block type?

viewController.h
@property (strong, nonatomic) NSDictionary *locationIDsDictionary;

viewController.m
    [[LPAuthClient sharedClient]GET:getLocationIDString parameters:nil success:^(NSURLSessionDataTask *task, id responseObject) {
        NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)task.response;
        if (httpResponse.statusCode == 200) {
            dispatch_async(dispatch_get_main_queue(), ^{

                _locationArray = responseObject[@"data"];
                NSLog(@"Response %@", responseObject);
            });
        }

    } failure:^(NSURLSessionDataTask *task, NSError *error) {
        NSLog(@"Failure %@", error);
    }];

    NSLog(@"locationIDsDictionary %@", _locationIDsDictionary);

EDIT: Output

 Response {
data =     (
            {
        id = 45388148;
        latitude = "37.785834";
        longitude = "-122.406417";
        name = "TESTING HATE VENUE";
    },
            {
        id = 208947000;
        latitude = "37.785834";
        longitude = "-122.406417";
        name = "The Greatest Isreal";
    },
            {
        id = 86128772;
        latitude = "37.785834";
        longitude = "-122.406417";
        name = "Pike street";
    },
            {
        id = 33208867;
        latitude = "37.785834";
        longitude = "-122.406417";
        name = abcde;
    },
            {
        id = 104267842;
        latitude = "37.785834";
        longitude = "-122.406417";
        name = "somewhere over south dakota";
    },
            {
        id = 232446516;
        latitude = "37.785834";
        longitude = "-122.406417";
        name = wow;
    },
            {
        id = 107511313;
        latitude = "37.785834";
        longitude = "-122.406417";
        name = "Yum Yum.com";
    },
            {
        id = 189736241;
        latitude = "37.785834";
        longitude = "-122.406417";
        name = "wow;l";
    },
            {
        id = 246109339;
        latitude = "37.785834";
        longitude = "-122.406417";
        name = Fused;
    },
            {
        id = 153279132;
        latitude = "37.785834";
        longitude = "-122.406417";
        name = 333;
    },
            {
        id = 115790356;
        latitude = "37.785834";
        longitude = "-122.406417";
        name = "Bar Karma";
    },
            {
        id = 50341151;
        latitude = "37.785834";
        longitude = "-122.406417";
        name = popoopo;
    },
            {
        id = 121590347;
        latitude = "37.785834";
        longitude = "-122.406417";
        name = 26;
    },
            {
        id = 75286586;
        latitude = "37.785834";
        longitude = "-122.406417";
        name = wow;
    },
            {
        id = 72889805;
        latitude = "37.785834";
        longitude = "-122.406417";
        name = test;
    },
            {
        id = 284599098;
        latitude = "37.785834009";
        longitude = "-122.406416997";
        name = "Urban Safari";
    },
            {
        id = 89500038;
        latitude = "37.785835266";
        longitude = "-122.406417847";
        name = "Cali Home";
    },
            {
        id = 8736810;
        latitude = "37.785835266";
        longitude = "-122.406417847";
        name = "Test%20Test%20Test";
    },
            {
        id = 45031994;
        latitude = "37.78584";
        longitude = "-122.4064";
        name = japaneses;
    },
            {
        id = 35874897;
        latitude = "37.785806574";
        longitude = "-122.406477728";
        name = "Hotel Palomar Fifth Floor Restaurant";
    }
);
meta =     {
    code = 200;
};

}


Solution

  • To build on CrimsonChris' answer, the GET: parameters: success: method is asynchronous. In this code:

    [[LPAuthClient sharedClient] GET:getLocationIDString parameters:nil success:^(NSURLSessionDataTask *task, id responseObject) {
        NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)task.response;
        if (httpResponse.statusCode == 200) {
            dispatch_async(dispatch_get_main_queue(), ^{
                _locationArray = responseObject[@"data"];
                NSLog(@"Response %@", responseObject);
            });
        }
    } failure:^(NSURLSessionDataTask *task, NSError *error) {
        NSLog(@"Failure %@", error);
    }];
    NSLog(@"locationIDsDictionary %@", _locationIDsDictionary);
    

    The success parameter is your completion block so:

    ^(NSURLSessionDataTask *task, id responseObject) {
        NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)task.response;
        if (httpResponse.statusCode == 200) {
            dispatch_async(dispatch_get_main_queue(), ^{
                _locationArray = responseObject[@"data"];
                NSLog(@"Response %@", responseObject);
            });
        }
    } failure:^(NSURLSessionDataTask *task, NSError *error) {
        NSLog(@"Failure %@", error);
    }
    

    is only called when iOS completes your download task, so your dictionary is only being allocated when the download task completes. Meanwhile, the remaining lines of code are being executed, hence the meaning of asynchronous - performed on a different thread. If it was synchronous, the code would be halted until that block of code is finished, which is bad and you see it translated into freezy UI in iOS apps.

    So NSLog(@"locationIDsDictionary %@", _locationIDsDictionary); is still called while your download task is being performed, hence it will evaluate to nil - that is of course unless your internet speed is insane :)