AFNetworking-2 waitUntilFinished无法正常工作 [英] AFNetworking-2 waitUntilFinished not working

查看:101
本文介绍了AFNetworking-2 waitUntilFinished无法正常工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道另一个类似的问题,但它适用于旧版AFNetworking,并且无论如何都没有真正回答它。

I know there is another similar question, but it's for an older version of AFNetworking, and doesn't really answer it anyway.

我有以下代码:

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);
...

如果我运行这个,我会在日志中看到的是:

If I run this, what I'll see in my log is:

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 = "";
}

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

The NSLog that is after the waitUntilFinished fires first. I expected it to fire second. What am I missing?

推荐答案

一些想法:


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

  1. The issue is that waitUntilFinished will wait for the core network operation to complete, but it will not wait for the success or failure completion blocks. If you want to wait for the completion blocks, you can use a semaphore:

__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 完成块中发布 isFinished ,消除信号量在此过程中。

You can, alternatively, wrap this in your own concurrent NSOperation subclass, posting isFinished in the AFHTTPRequestOperation completion blocks, eliminating the semaphore in the process.

注意,如果在信号量上执行信号量,请务必指定 completionQueue 主队列
因为,如果没有,AFNetworking默认将调度完成处理程序分配到主队列,你可以死锁。

Note, make sure to specify completionQueue if doing semaphores on the main queue because, in the absence of that, AFNetworking defaults to dispatching completion handlers to the main queue and you can deadlock.

顺便说一句,你永远不应该阻止主队列(可怜的用户体验,你的应用程序可能会被看门狗进程杀死等),所以如果你'从主队列中执行此操作,我不鼓励使用 waitUntilFinished 或信号量。最好只在完成块中启动您需要的任何内容,让主队列在此异步网络操作正在进行时继续执行,例如:

As an aside, you should never block the main queue (poor UX, your app could be killed by watchdog process, etc.), so if you're doing this from the main queue, I'd discourage the use of either waitUntilFinished or the semaphore. It's better to just initiate whatever you need from within the completion blocks, letting the main queue continue execution while this asynchronous network operation is in progress, e.g.:

[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做任何必要的更新。因此,您可以使用自己的块参数,以便视图控制器可以告诉模型对象完成后要做什么(而不是使用 waitUntilFinished 或信号量来进行网络操作阻止主队列)。例如,假设你的模型有这样的方法:


It sounds like you want to let your model let the UI do any necessary updates when the model object is done doing its updates. So, you can use your own block parameters so that the view controller can tell the model object what to do when its done (instead of using waitUntilFinished or semaphore to make the network operation block the main queue). For example, let's assume your model had some method like this:

- (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);
                                             }];
}

然后您的视图控制器可以执行以下操作:

Then your view controller can do something like:

[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使用的相同样式的完成块。如果您希望模型返回信息,您可以将其他参数添加到完成块本身,但我认为上面说明了基本概念。

Bottom line, your code can use the same style of completion blocks that AFNetworking uses. If you want the model to pass information back, you can add additional parameters to the completion blocks, themselves, but I presume the above illustrates the basic idea.

这篇关于AFNetworking-2 waitUntilFinished无法正常工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆