【问题标题】:AFNetworking 3.0 AFHTTPSessionManager using NSOperationAFNetworking 3.0 AFHTTPSessionManager 使用 NSOperation
【发布时间】:2016-04-17 16:01:09
【问题描述】:

我现在被困了一段时间,我需要帮助。所以在 AFNetworking 2.0 我们有AFHTTPRequestOperation 所以我可以很容易地使用NSOperationQueue 并且有一些依赖。所以我们现在只有AFHTTPSessionManagerNSURLSession,它们不是NSOperation的子类。我有类APIClientAFHTTPSessionManager 的子类。我将该类用作sharedClient 的单例。我已经覆盖了 GET 和 POST,例如 GET 看起来是这样的:

- (NSURLSessionDataTask *)GET:(NSString *)URLString
               parameters:(NSDictionary *)parameters
                  success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
                  failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure {
NSURLSessionDataTask *task = [super GET:URLString parameters:parameters success:^(NSURLSessionDataTask *task, id responseObject) {
    success(task, responseObject);
} failure:^(NSURLSessionDataTask *task, NSError *error) {
    failure(task, [Response createErrorWithAFNetworkingError:error]);
}];

return task;
}

您知道如何以这种方式(如果可能的话)将其包装为NSOperation 吗?所以我想做的是-我希望能够并行运行两个网络调用,然后再进行另一个方法调用,该方法调用取决于前两个调用的第二个网络调用。你知道什么是最好的方法吗?

【问题讨论】:

  • 是的,如果你不介意的话,请
  • 非常感谢。是的,哦,对不起,当我再次阅读时我还不够清楚 - 取决于两个请求:)
  • 如果你想在服务器端得到准确的错误,你可以查看这个答案'stackoverflow.com/a/35723726/3463712'

标签: ios objective-c afnetworking nsurlsession


【解决方案1】:

我已经编写了一组快速的类 (https://github.com/robertmryan/AFHTTPSessionOperation/),它们将 AFHTTPSessionManager 请求包装在异步 NSOperation 子类中。然后,您可以使用它来享受maxConcurrentOperation 约束或操作依赖关系。

例如,下面是一个示例,我们发出两个并发请求,并根据这两个请求的完成进行完成操作:

//  ViewController.m

#import "ViewController.h"
#import "AFNetworking.h"
#import "AFHTTPSessionOperation.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    NSString *urlString1 = @"...";
    NSString *urlString2 = @"...";

    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];

    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    queue.name = @"AFHTTPSessionManager queue";

    NSOperation *completionOperation = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"All done");
    }];

    NSOperation *op1 = [AFHTTPSessionOperation operationWithManager:manager HTTPMethod:@"GET" URLString:urlString1 parameters:nil uploadProgress:nil downloadProgress:nil success:^(NSURLSessionDataTask *task, id responseObject) {
        NSLog(@"finished 1");
    } failure:^(NSURLSessionDataTask *task, NSError *error) {
        NSLog(@"failed 1 - error = %@", error.localizedDescription);
    }];
    [completionOperation addDependency:op1];

    NSOperation *op2 = [AFHTTPSessionOperation operationWithManager:manager HTTPMethod:@"GET" URLString:urlString2 parameters:nil uploadProgress:nil downloadProgress:nil success:^(NSURLSessionDataTask *task, id responseObject) {
        NSLog(@"finished 2");
    } failure:^(NSURLSessionDataTask *task, NSError *error) {
        NSLog(@"failed 2 - error = %@", error.localizedDescription);
    }];
    [completionOperation addDependency:op2];

    [queue addOperations:@[op1, op2] waitUntilFinished:false];
    [[NSOperationQueue mainQueue] addOperation:completionOperation];  // do this on whatever queue you want, but often you're updating UI or model objects, in which case you'd use the main queue
}

@end

值得注意的是,由于您只处理两个请求,您还可以使用调度组来完成同样的事情:

//  ViewController.m

#import "ViewController.h"
#import "AFNetworking.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    NSString *urlString1 = @"...";
    NSString *urlString2 = @"...";

    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];

    dispatch_group_t group = dispatch_group_create();

    dispatch_group_enter(group);
    [manager GET:urlString1 parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        NSLog(@"finished 1");
        dispatch_group_leave(group);
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        NSLog(@"failed 1 - error = %@", error.localizedDescription);
        dispatch_group_leave(group);
    }];

    dispatch_group_enter(group);
    [manager GET:urlString2 parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        NSLog(@"finished 2");
        dispatch_group_leave(group);
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        NSLog(@"failed 2 - error = %@", error.localizedDescription);
        dispatch_group_leave(group);
    }];

    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"All done");
    });
}

@end

使用调度组,您只需要注意successfailure 块中的每个路径都调用dispatch_group_leave

【讨论】:

  • 这正是我想要的,太好了:)
  • 首先,我永远不会回到 2.x。如果我需要操作,我只需将 v3 任务包装在 NSOperation 子类中。其次,如果你真的要按顺序运行这些(并承受相应的性能损失),那么操作和调度组都不需要:只需在前一个完成时启动每个。
  • @Lion 是的,它是一种递归(尽管因为事情是异步发生的,所以将很多东西塞进堆栈的一些更丑陋的问题与这里无关)。但请注意,仅在绝对必要时才执行这种类型的顺序请求(即构建一个请求所需的信息需要先前请求提供的信息),因为您为顺序请求付出了巨大的惩罚。设计允许您同时发出请求的解决方案要好得多。
  • @Aviva - 您使用的是最新版本的 AFNetworking 还是旧版本?早期版本没有这些进度参数。如果您使用的是最新版本的 AFNetworking,它应该可以正常工作。我刚刚用最新版本的 AFNetworking 测试了上面的代码,没有出现任何问题。
  • 你能分享错误的全文吗?不要只看error.localizedDescription,让我们看看整个NSError。让我们确保错误不是无关的(例如,可能在没有适当的 Info.plist 设置以允许不安全的网络连接的情况下尝试连接到 http 资源(而不是 https))。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-02-19
  • 1970-01-01
  • 2017-03-04
  • 2014-08-02
  • 1970-01-01
  • 1970-01-01
  • 2014-09-25
相关资源
最近更新 更多