簡體   English   中英

從異步回調傳遞數據

[英]passing data from async callback

由於某些原因,我需要從異步回調傳遞數據,

如果目標是全局變量,那沒什么大不了的,

但是變量僅在方法中使用,所以我希望可以在方法中使用。

- (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

無論如何,我可以從異步回調訪問數據,但不能通過全局變量或委托訪問數據?

因為我只需要這些數據作為登錄方法。

由於您似乎具有JavaScript背景,因此您可能對promises很熟悉。

在Objective-C中,有一些實現諾言的庫。 利用承諾庫的方法可能看起來像這樣:

您的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

您可以定義這樣的類變量,並在類中的任何位置使用它:

喜歡:

@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?");
    }];

    ...
}

我找到了一個不錯的異步控制流庫Sequencer ,我喜歡這個解決方案,就像Node.js中的async一樣:)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM