ios - AFNetworking-2 waitUntilFinished 不工作

标签 ios objective-c afnetworking-2

我知道有 another similar question ,但它适用于旧版本的 AFNetworking,并且无论如何都没有真正回答它。

我有以下代码:

AFHTTPRequestOperationManager* manager = [AFHTTPRequestOperationManager manager];
manager.securityPolicy.allowInvalidCertificates = YES;
manager.requestSerializer = [AFJSONRequestSerializer serializer];
[manager.requestSerializer setAuthorizationHeaderFieldWithUsername: currentUser() password: currentPassword()];
__block NSDictionary* response = nil;
AFHTTPRequestOperation* operation = [manager
    GET: @"https://10.20.30.40:8765/foobar"
    parameters: [NSDictionary dictionary]
    success:^(AFHTTPRequestOperation* operation, id responseObject){
        response = responseObject;
        NSLog(@"response (block): %@", response);
    }
    failure:^(AFHTTPRequestOperation* operation, NSError* error){
        NSLog(@"Error: %@", error);}
];
[operation waitUntilFinished];
NSLog(@"response: %@", response);
...

如果我运行它,我将在我的日志中看到的是:

2013-12-09 09:26:20.105 myValve[409:60b] response: (null)
2013-12-09 09:26:20.202 myValve[409:60b] response (block): {
    F00005 = "";
    F00008 = "";
    F00013 = "";
}

waitUntilFinished 之后NSLog 首先触发。我预计它会第二次开火。我错过了什么?

最佳答案

几个想法:

  1. 问题是waitUntilFinished 将等待核心网络操作完成,但不会等待成功失败完成 block 。如果你想等待完成 block ,你可以使用信号量:

    __block NSDictionary* response = nil;
    
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    
    manager.completionQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    AFHTTPRequestOperation* operation = [manager GET: @"https://10.20.30.40:8765/foobar"
                                          parameters: [NSDictionary dictionary]
                                             success:^(AFHTTPRequestOperation* operation, id responseObject){
                                                 response = responseObject;
                                                 NSLog(@"response (block): %@", response);
                                                 dispatch_semaphore_signal(semaphore);
                                             }
                                             failure:^(AFHTTPRequestOperation* operation, NSError* error){
                                                 NSLog(@"Error: %@", error);
                                                 dispatch_semaphore_signal(semaphore);
                                             }];
    
    NSLog(@"waiting");
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    // [operation waitUntilFinished];
    NSLog(@"response: %@", response);
    

    或者,您可以将其包装在您自己的并发 NSOperation 子类中,在 AFHTTPRequestOperation 完成 block 中发布 isFinished,消除 进程中的信号量

    注意,如果在主队列上执行信号量,请确保指定 completionQueue 因为,在没有它的情况下,AFNetworking 默认将完成处理程序分派(dispatch)到主队列,您可能会死锁。

  2. 顺便说一句,你永远不应该阻塞主队列(糟糕的用户体验,你的应用程序可能会被看门狗进程杀死,等等),所以如果你从主队列这样做,我会劝阻waitUntilFinished 或信号量的使用。最好从完成 block 中启动任何你需要的东西,让主队列在这个异步网络操作正在进行时继续执行,例如:

    [activityIndicatorView startAnimating];
    
    AFHTTPRequestOperation* operation = [manager GET: @"https://10.20.30.40:8765/foobar"
                                          parameters: [NSDictionary dictionary]
                                             success:^(AFHTTPRequestOperation* operation, id responseObject){
    
                                                 // do whatever you want with `responseObject` here
    
                                                 // now update the UI, e.g.:
    
                                                 [activityIndicatorView stopAnimating];
                                                 [self.tableView reloadData];
                                             }
                                             failure:^(AFHTTPRequestOperation* operation, NSError* error){
    
                                                 // put your error handling here
    
                                                 // now update the UI, e.g.:
    
                                                 [activityIndicatorView stopAnimating];
                                             }];
    
    // NSLog(@"waiting");
    // dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    // // [operation waitUntilFinished];
    // NSLog(@"response: %@", response);
    

听起来您想让您的模型让 UI 在模型对象完成更新后进行任何必要的更新。因此,您可以使用自己的 block 参数,以便 View Controller 可以告诉模型对象在完成时做什么(而不是使用 waitUntilFinished 或信号量来使网络操作阻塞主队列)。例如,假设您的模型有这样的方法:

- (void)updateModelWithSuccess:(void (^)(void))success failure:(void (^)(NSError *error))failure
{
    AFHTTPRequestOperationManager* manager = [AFHTTPRequestOperationManager manager];
    manager.securityPolicy.allowInvalidCertificates = YES;
    manager.requestSerializer = [AFJSONRequestSerializer serializer];
    [manager.requestSerializer setAuthorizationHeaderFieldWithUsername: currentUser() password: currentPassword()];
    AFHTTPRequestOperation* operation = [manager GET: @"https://10.20.30.40:8765/foobar"
                                          parameters: [NSDictionary dictionary]
                                             success:^(AFHTTPRequestOperation* operation, id responseObject){

                                                 // do your model update here

                                                 // then call the success block passed to this method (if any),
                                                 // for example to update the UI

                                                 if (success)
                                                     success();
                                             }
                                             failure:^(AFHTTPRequestOperation* operation, NSError* error){
                                                 NSLog(@"Error: %@", error);

                                                 // if caller provided a failure block, call that

                                                 if (failure)
                                                     failure(error);
                                             }];
}

然后你的 View Controller 可以做类似的事情:

[modelObject updateModelWithSuccess:^{
    // specify UI updates to perform upon success, e.g.
    // stop activity indicator view, reload table, etc.
} failure:^(NSError *error){
    // specify any UI updates to perform upon failure
}]

最重要的是,您的代码可以使用 AFNetworking 使用的相同样式的完成 block 。如果您希望模型将信息传回,您可以向完成 block 本身添加额外的参数,但我认为以上说明了基本思想。

关于ios - AFNetworking-2 waitUntilFinished 不工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20476957/

相关文章:

iphone - 如何检测完整的 body ,如手、腿?

ios - UITableView,如何以编程方式更改整个表格 View 的宽度和高度?

ios - 无法在 ios 中使用 afnetworking 发布 JSON

iOS App - 如何使用 AFNetworking 2 实现自动 session cookie 刷新

objective-c - 带凭据的 AFNetworking 上传任务(HTTP 基本身份验证)

ios - 获取 UIScrollView 中 View 的 y 位置

ios - 应用程序在更新 UITableView 中显示的 CoreData 模型后崩溃

objective-c - 错误 "No architectures to compile for (ONLY_ACTIVE_ARCH=YES, active arch=x86_64, VALID_ARCHS=armv7 armv7s)."?

ios - 在 Xcode 上创建配置文件

ios - 创建可以在单个 View Controller 上显示的单独菜单的最标准方法是什么