由于某些原因,我需要从异步回调传递数据,
如果目标是全局变量,并不是什么大事,
但变量只是在方法中使用,所以我希望我能在方法中做到。
- (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
无论如何我可以从异步回调中访问数据,但不能通过全局变量或委托访问?
因为我只需要这个数据用于登录方法。
答案 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中的异步一样:)