如何同步使用AFNetworking 2.0

4

我在寻找如何同步运行AFNetworking 2.0的示例和教程时搜索了很多,但只找到了针对AFNetworking 1.0的解决方案。我找到了以下内容:

Can AFNetworking return data synchronously (inside a block)?

下面是我的示例:

- (User *)getUserWithUsername: (NSString *) username andPassword: (NSString *) password {

    NSDictionary *params = @{@"email": username, @"password": password};


    [[DCAPIClient sharedClient] POST:@"login" parameters:params success:^(NSURLSessionDataTask * __unused task, id JSONResult) {
        NSLog(@"JSON %@", JSONResult);
        BOOL errorCode = [JSONResult objectForKey:@"error"];
        if (!errorCode) {
            self.username = [JSONResult objectForKey:@"name"];            
            // Fill the attributes
            // self.email = .. a
         } else {
            // error with login show alert
         }

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

     // this does not work
     //[[[DCAPIClient sharedClient] operationQueue] waitUntilAllOperationsAreFinished];


     if (self.username == nil) {
         return nil;
     }

     return self;

}

但这并不起作用,因为首先调用了if (self.username == nil)

我该如何使AFNetworking 2.0库同步运行,以便我可以返回响应?

DCAPIClient:AFHTTPSessionManager

+ (instancetype)sharedClient {
    static DCAPIClient *_sharedClient = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _sharedClient = [[DCAPIClient alloc] initWithBaseURL:[NSURL URLWithString:DCAPIBaseURLString]];
        _sharedClient.responseSerializer = [AFJSONResponseSerializer serializer];
    });

    return _sharedClient;
}
3个回答

5

有些人总是喜欢妨碍别人,但有时候你只想让你的HTTP调用同步执行。

为此,您可以使用AFNetworking-Synchronous库。它向AFHTTPRequestOperationManager添加了一个方便的类别,其中包含诸如syncGETsyncPOST之类的同步方法,这些方法在内部使用AFNetworking的waitUntilFinished实现同步调用。


将HTTP请求设置为同步不是一个好的实践。请注意,任何使用阻塞调用的“同步”程序都可以仅使用异步调用来实现异步。一旦您熟悉了异步编程习惯用语,它通常不比同步样式更“困难” ;) 如果您想学习这种技术并释放其力量,那就由您决定 :) - CouchDeveloper
1
@CouchDeveloper 请参考我的回答中的第一句话,关键词是“有时候”。 - yonilevy

0

我不确定你为什么要这样做,但一个解决方案是使用回调块。就像这样:

- (void)getUserWithUsername: (NSString *) username andPassword: (NSString *) password success:(void (^)(User *user))success failure:(void (^)(NSError *error))failure
{
    NSDictionary *params = @{@"email": username, @"password": password};

    __weak __typeof(self)weakSelf = self;    

    [[DCAPIClient sharedClient] POST:@"login" parameters:params success:^(NSURLSessionDataTask * __unused task, id JSONResult) {

        BOOL errorCode = [JSONResult objectForKey:@"error"];
        if (!errorCode) {
            weakSelf.username = [JSONResult objectForKey:@"name"];

            if (weakSelf.username == nil) {
                failure(nil);
            }else{
                success(weakSelf)
            }
        } else {
            failure(nil);
        }

    } failure:^(NSURLSessionDataTask *__unused task, NSError *error) {
         failure(error);
    }];
}

0

你不应该将本质上异步的方法变成同步的,而是应该使调用方也变成异步的。

也就是说,你的方法变成了异步的,并提供了一个完成处理程序:

- (void) userWithUsername:(NSString *)username 
                 password:(NSString *)password 
               completion:(completion_handler_t)completion;

completion_handler_t是一种类型定义,可以在头文件中声明如下:

typedef void (^completion_handler_t)(User*, NSError*);

请注意,使用 typedef 是可选的,但可能会使您的代码更易于理解。
然后,您可以按以下方式使用它:
[self userWithUsername:username 
              password:password 
            completion:^(User* user, NSError*error){
    // Check error; do something with user
    ...
}];

您可以按照以下方式实现:
- (void) userWithUsername:(NSString *)username 
                 password:(NSString *)password 
               completion:(completion_handler_t)completion
{
    NSDictionary *params = @{@"email": username, @"password": password};
    [[DCAPIClient sharedClient] POST:@"login" parameters:params   
        success:^(NSURLSessionDataTask * __unused task, id JSONResult) {
            NSLog(@"JSON %@", JSONResult);
            BOOL errorCode = [JSONResult objectForKey:@"error"];
            if (!errorCode) {
                self.username = [JSONResult objectForKey:@"name"];            
                // Fill the attributes
                // self.email = .. a
                if (completion) {
                    completion(theUser, nil);  // completion(self, nil)?? 
                }
            } else {
                if (completion) {
                    completion(nil, error);
                }
            }

        } failure:^(NSURLSessionDataTask *__unused task, NSError *error) {
             if (completion) {
                 completion(nil, error);
             }
        }];
}

我得到了编译器错误:completion:(completion_handler_t)completion 需要一个类型。 - Bernard
@Bernard 你可能没有定义 completion_handler_t 类型。我编辑了我的答案,其中包括类型定义。请注意,typedef 是某种 _别名_,通常是实际类型的更可读版本。这个 typedef 放在头文件中。故意将其放在声明使用该类型的公共方法的类定义正上方。 - CouchDeveloper

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接