从异步回调传递数据

时间:2014-05-16 05:25:09

标签: ios objective-c afnetworking grand-central-dispatch

由于某些原因,我需要从异步回调传递数据,

如果目标是全局变量,

并不是什么大事,

但变量只是在方法中使用,所以我希望我能在方法中做到。

- (void)login
{
    dispatch_group_t login_group = dispatch_group_create();

    NSString* secureToken = nil;
    NSString* loginSeed = nil;

    [self getSecureToken:&secureToken group:login_group];
    [self getLoginSeed:&loginSeed group:login_group];

    dispatch_group_notify(login_group, dispatch_get_main_queue(), ^{
        NSLog(@"token: %@", secureToken);
    });
}

- (void)getSecureToken:(NSString **)token group:(dispatch_group_t)group
{
    dispatch_group_enter(group);

    [_manager setResponseSerializer:[AFHTTPResponseSerializer serializer]];
    [_manager GET:@"/secure_token" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {

        //get secure token
        NSDictionary* result = [NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingMutableContainers error:nil];
        *token = [result objectForKey:@"SECURE_TOKEN"];
        dispatch_group_leave(group);

    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        dispatch_group_leave(group);
    }];
}

如果我这样做,那么它将打印 null

无论如何我可以从异步回调中访问数据,但不能通过全局变量或委托访问?

因为我只需要这个数据用于登录方法。

3 个答案:

答案 0 :(得分:1)

由于您似乎拥有JavaScript背景,因此您可能熟悉 promises

在Objective-C中有一些实现promise的库。使用promise库的方法可能看起来像这样:

您的login将变为异步(不可避免):

- (Promise*)promiseLogin {
    return [self promiseSecureToken]
    .then(^id(NSString* secureToken){
        return [self promiseLoginWithToken:secureToken seed:seed];    
    }, nil);
}

您的方法promiseSecureToken可以按如下方式实施:

- (Promise*) promiseSecureToken
{
    Promise* promise = [[Promise alloc] init];
    [_manager setResponseSerializer:[AFHTTPResponseSerializer serializer]];
    [_manager GET:@"/secure_token" parameters:nil 
                                   success:^(AFHTTPRequestOperation *operation, id responseObject) 
    {
        //get secure token
        NSError* error;
        NSDictionary* result = 
           [NSJSONSerialization JSONObjectWithData:responseObject
                                           options:NSJSONReadingMutableContainers 
                                             error:&error];
        if (result) {
            NSString* token = [result objectForKey:@"SECURE_TOKEN"];
            [promise fulfillWithValue:token];
        }
        else {
            [promise rejectWithReason:error];
        }
    } 
    failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        [promise rejectWithReason:error];
    }];

    return promise;
}

您可以这样使用它:

[self promiseLogin]
.then(^id(id result){
    // "result" is whatever promiseLoginWithToken:seed: returns
    return something;
},nil)
.then(nil, ^id(NSError*error){
    // catch ANY error, no matter where it occurred in the previous tasks:
    NSLog(@"ERROR: %@", error);
    return nil;
});

有关库列表和更多有用信息,请查看此处:https://softwareengineering.stackexchange.com/questions/184597/success-failure-blocks-vs-completion-block/219929#219929

答案 1 :(得分:0)

您可以像这样定义一个类变量,并在类中的任何位置使用它:

像:

@interface MyViewController()
{
    NSString *token;
}

@end

@implementation MyViewController()

...

否则,您还可以尝试为getSecureToken方法使用完成块?

像这样:

- (void)getSecureToken:(NSString **)token group:(dispatch_group_t)group onComplete:(void(^)(AFHTTPRequestOperation *operation, id responseObject))success onFail:(void(^)(AFHTTPRequestOperation *operation, NSError *error))fail
{
    dispatch_group_enter(group);

    [_manager setResponseSerializer:[AFHTTPResponseSerializer serializer]];
    [_manager GET:@"/secure_token" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {

        //get secure token
        NSDictionary* result = [NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingMutableContainers error:nil];
        *token = [result objectForKey:@"SECURE_TOKEN"];
        dispatch_group_leave(group);



        // ---------------------------------------------------------
        // Check completion block param exists before executing it
        // ---------------------------------------------------------
        if(success)
        {
            success(operation, result);
        }




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

        if(fail)
        {
            fail(operation, error);
        }
    }];
}

然后你可以去:

- (void)login
{
    dispatch_group_t login_group = dispatch_group_create();

    NSString* secureToken = nil;
    NSString* loginSeed = nil;

    [self getSecureToken:&secureToken group:login_group onSuccess:^(AFHTTPRequestOperation *operation, id responseObject){

        NSLog(@"token is = %@", [responseObj valueForKey:@"token"]);        

    } onFail:^(AFHTTPRequestOperation *operation, NSError *error) {
        NSLog(@"Failed to get token?");
    }];

    ...
}

答案 2 :(得分:0)

我找到了一个不错的异步控制流库Sequencer, 我喜欢这个解决方案,就像Node.js中的异步一样:)