Getting variable from the inside of block [duplica

2019-07-27 13:14发布

I'm using AFNetworking 2 to GET data from server and I need to get back the responseObject but no matter what I do i still get <null>.

Here is the method which is sending GET request to server and in response it gets NSDictionary which I want to use in another method...

- (void)getCurrentVersionsForTimetableWithID:(NSString *)timetableID
{
    [[AFHTTPRequestOperationManager manager] GET:[NSString stringWithFormat:VERSIONS, timetableID] parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
        // Here I want to get responseObject
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        NSLog(@"Couldn't get current versions: %@", [error localizedDescription]);
    }];
}

If I call this method everything works fine. But when I try to make it return NSDictionary like this:

- (NSDictionary *)getCurrentVersionsForTimetableWithID:(NSString *)timetableID
{
    __block NSDictionary *currentVersions;

    [[AFHTTPRequestOperationManager manager] GET:[NSString stringWithFormat:VERSIONS, timetableID] parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
        currentVersions = responseObject;
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        NSLog(@"Couldn't get current versions: %@", [error localizedDescription]);
    }];

    return currentVersions;
}

I get <null> value. I know this is happening because of async but how to solve this? I've tried to pass another completion block to this method but when I call it inside another one I still cannot assign the result to the variable... Please guys, help me!

3条回答
Fickle 薄情
2楼-- · 2019-07-27 13:47

I'm sure the problem with async calls, threads run in parallel and you return nil before you get actual data, so easy way (not the prefect! :) ) is to make it synchronous to wait for result:

try:

- (NSDictionary *)getCurrentVersionsForTimetableWithID:(NSString *)timetableID
{
    dispatch_semaphore_t sema = dispatch_semaphore_create(0);

    __block NSDictionary *currentVersions;

    [[AFHTTPRequestOperationManager manager] GET:[NSString stringWithFormat:VERSIONS, timetableID] parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
        currentVersions = responseObject;
        dispatch_semaphore_signal(sema);
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        NSLog(@"Couldn't get current versions: %@", [error localizedDescription]);
    }];

    while (dispatch_semaphore_wait(sema, DISPATCH_TIME_NOW))
    {
        [[NSRunLoop currentRunLoop]
         runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0]];
    }

    return currentVersions;
}

or better to use Michaels answer to return in completion block if you need it async, its a good way to return cached data before actual data coming.

查看更多
不美不萌又怎样
3楼-- · 2019-07-27 14:05

Try this, I dont remember how a blocks is created in my head and im not on my mac. But i think its like this.

__block NSDictionary *currentVersions;

void (^success)(AFHTTPRequestOperation, id) = ^(AFHTTPRequestOperation *operation, id responseObject) {

    currentVersions = responseObject;
}

[[AFHTTPRequestOperationManager manager] GET:[NSString stringWithFormat:VERSIONS, timetableID] parameters:nil success:success
 failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    NSLog(@"Couldn't get current versions: %@", [error localizedDescription]);
}];
查看更多
成全新的幸福
4楼-- · 2019-07-27 14:11

You want to pass in a completion block that takes NSDictionary as parameter:

- (void)getCurrentVersionsForTimetableWithID:(NSString *)timetableID completion:(void (^)(NSDictionary* currentVersions))completion
{
    [[AFHTTPRequestOperationManager manager] GET:[NSString stringWithFormat:VERSIONS, timetableID] parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
        currentVersions = responseObject;

        if(completion){
            completion(currentVersions);
        }
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        NSLog(@"Couldn't get current versions: %@", [error localizedDescription]);
    }];
}

To use it:

[self getCurrentVersionsForTimetableWithID:@"someId" 
                                completion:^(NSDictionary* currentVersions){
                                    // Do something with currentVersions
                                }];
查看更多
登录 后发表回答