リクエストのタイムアウトや接続がオフラインになったときなどの「一般的な」エラーを処理する方法を探しています。
基本的に、AFHTTPSessionManager の複数の (シングルトン) サブクラスがあり、それぞれが異なるサーバーへの要求を処理するクライアントを表します。各クライアントはinitWithBaseURL
、AFNetworking の作成者が推奨するようにオーバーライドすることによってセットアップされます。これは、要求/応答シリアライザーと汎用ヘッダーが設定される場所です。サンプルクライアントは次のとおりです。
@implementation APIClient
+ (APIClient *)sharedClient {
static APIClient *sharedClient = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedClient = [[self alloc] initWithBaseURL:[NSURL URLWithString:@"baseurl.goes.here"]];
});
return sharedClient;
}
- (instancetype)initWithBaseURL:(NSURL *)url
{
self = [super initWithBaseURL:url];
if(self) {
// Setup goes here
self.requestSerializer = [AFHTTPRequestSerializer serializer];
self.requestSerializer.timeoutInterval = 20.0f;
self.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"text/plain", @"text/html", nil];
[AFNetworkActivityIndicatorManager sharedManager].enabled = YES;
[AFNetworkActivityLogger sharedLogger].level = AFLoggerLevelDebug;
[[AFNetworkActivityLogger sharedLogger] startLogging];
}
return self;
}
- (void)startPostRequestWithPath:(NSString *)path parameters:(NSDictionary *)parameters successBlock:(APISuccessBlock)success failureBlock:(APIFailureBlock)failure
{
[self POST:path parameters:parameters
success:^(NSURLSessionDataTask * _Nonnull task, id _Nonnull responseObject) {
success(responseObject);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
if(isGenericError) {
// Do something generic here
}
else {
failure(error);
}
}];
}
モデル (Post など) 内には、View Controller が独自の成功/失敗ブロックをクライアントに渡すことでデータをフェッチするために使用できる静的メソッドがあります。したがって、次のようになります。
View Controller --> Model --> Client --> Model --> View Controller.
そして、これがモデルの実装です
@implementation Post
+ (void)fetchLatestPost:(void (^)(Post *parsedData, NSError *error))completion
{
[[APIClient sharedClient] startRequestWithPath:kIndexPath
parameters:nil
requestType:RequestTypePost
successBlock:^(id data) {
NSError *parsingError = nil;
Post *post = [[Index alloc] initWithDictionary:data error:&err];
completion(index, nil);
}
failureBlock:^(NSError *error) {
completion(nil, error);
}
];
}
View Controller がその Post をフェッチしようとしてリクエストがタイムアウトした場合、画面の内容を非表示にして更新ボタンを表示したいと思います。このロジックは BaseViewController に実装されているため、すべてのビュー コントローラーで再利用できます。問題は、そのボタンがクリックされたときに SAME リクエストを再開するにはどうすればよいかということです。ビュー コントローラは、異なるメソッド シグネチャを持つ異なるモデルから複数のリクエストを作成できることに注意してください。私はこれをまったく理解できないように見えるので、どんな助けも大歓迎です。
以前はデリゲートを使用してこれを処理していましたが、BaseViewController は「一般的な」デリゲート メソッドを実装していました。ただし、ブロックに切り替えようとしてきましたが、利点はありますが、ビューコントローラーの障害ブロックを「オーバーライド」できないため、 BaseViewController を使用できません。