web-dev-qa-db-ja.com

NSOperationを使用したAFNetworking 3.0 AFHTTPSessionManager

私はしばらくの間立ち往生しており、助けが必要です。 AFNetworking 2.0にはAFHTTPRequestOperationがあるので、NSOperationQueueを簡単に使用でき、いくつかの依存関係があります。したがって、ここにあるのはAFHTTPSessionManagerNSURLSessionだけで、サブクラスNSOperationはありません。 APIClientをサブクラス化するクラスAFHTTPSessionManagerがあります。私はそのクラスを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としてラップする方法で実装する方法はありますか?だから私がやりたいこと-私は2つのネットワーク呼び出しを並行して実行できるようにしたいと思っています。その後、最初の2つの呼び出しの2番目のネットワーク呼び出しに依存する別のメソッド呼び出しを行います。何が最善のアプローチとなるか考えていますか?

14
Flipper

非同期のAFHTTPSessionManagerサブクラスでNSOperationリクエストをラップするクラスの小さなセット( https://github.com/robertmryan/AFHTTPSessionOperation/ )を書きました。その後、それを使用してmaxConcurrentOperation制約、または操作の依存関係を楽しむことができます。

たとえば、次の例では、2つの同時要求を発行し、これらの両方の要求の完了に応じて完了操作を行います。

//  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

2つのリクエストしか処理しないので、ディスパッチグループを使用して同じことを実行することもできます。

//  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

ディスパッチグループを使用する場合、successブロックとfailureブロック内のすべてのパスがdispatch_group_leaveを呼び出すように注意する必要があります。

34
Rob