AFNETWORKING 2.0 ResponseObjectの処理
-
20-12-2019 - |
質問
質問があります。たぶん2つの質問。
最初の1つはこのコードに関連しています。
-(void)isLoggedIn {
NSString *urlString = [NSString stringWithFormat:@"%@%@%@", kBaseURL, kAPI, kUserIsLogged];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer = [AFJSONResponseSerializer serializerWithReadingOptions:NSJSONReadingAllowFragments];
[manager GET:urlString parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"JSON: %@", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"Error: %@", error);
}];
}
.
この方法は無効ではありません、私はそれがBOOLや私が使うことができる何かを返していることを望みます:ユーザーはログインしています> OKアプリのどこかに何かをしてください。ユーザーはログインしていません> OKユーザーに自分の資格情報を紹介してログインできる画面にユーザーに促します。
2番目の質問はこのコードに関連しています:
-(void)detail {
NSString *urlString = [NSString stringWithFormat:@"%@%@%@", kBaseURL, kAPI, kUser];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer = [AFJSONResponseSerializer serializerWithReadingOptions:NSJSONReadingAllowFragments];
[manager GET:urlString parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"JSON: %@", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"Error: %@", error);
}];
}
.
このメソッドは私が望んでいる場所を使うことができる解析されたJSONと私にNSArrayを返します。
このメソッドは、NetworkModel(NSObjectサブクラス)というモデルに含まれています。私はなぜ私がブロック内のすべてをするべきか疑問に思っています。私は場所をすべての場所にネットワークと対話する部分があるはずです。そして1つのユニークな場所/クラスで編成されていません。それをする方法はありますか。私はすべてのViewControllerすべてのリクエストを持ちたくありません。私は任意のViewControllerから呼び出すことができるメソッドを定義したい(必要に応じてヘッダーファイルをインポートします)。
提案? アドバイスに感謝します!
解決
2つのアプローチでこれを行うことができます。ブロックを使用するか、またはSemaphoreを使用して非同期リクエストを待つために、メソッドを変更することができます。
セマフォ(醜い方法)
-(BOOL)isLoggedIn {
__block BOOL isLoggedIn;
dispatch_semaphore_t waiter = dispatch_semaphore_create(0);
NSString *urlString = [NSString stringWithFormat:@"%@%@%@", kBaseURL, kAPI, kUserIsLogged];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer = [AFJSONResponseSerializer serializerWithReadingOptions:NSJSONReadingAllowFragments];
[manager GET:urlString parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"JSON: %@", responseObject);
isLoggedIn = YES;
dispatch_semaphore_signal(waiter);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"Error: %@", error);
isLoggedIn = NO;
dispatch_semaphore_signal(waiter);
}];
dispatch_group_wait(waiter, DISPATCH_TIME_FOREVER);
return isLoggedIn;
}
.
それをする正しい方法
-(void)isLoggedIn:(void(^)(BOOL isLoggedIn))completionBlock {
NSString *urlString = [NSString stringWithFormat:@"%@%@%@", kBaseURL, kAPI, kUserIsLogged];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer = [AFJSONResponseSerializer serializerWithReadingOptions:NSJSONReadingAllowFragments];
[manager GET:urlString parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"JSON: %@", responseObject);
completionBlock(YES);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"Error: %@", error);
completionBlock(NO);
}];
}
.
あなたの2番目の質問のために、あなたはリクエストが完了したときに呼び出されるか失敗したときに呼び出されるネットワーキングクラスにブロック変数を設定することができます。
とにかく私はあなたがブロックにまったく慣れていないと思います(あなたの2番目の質問のせいで)、あなたがそれらの好きになることを数回のブロックの後に考えると、コードのスニペットが少ない場合にコードが複雑ではないことがわかりますリクエストと解析を実行すると、それがそれらをデバッグして問題を見つけるのが簡単で、私がブロックで動作し始めたときにも私の訴訟でした。
ブロック変数を使って
@interface YourNetworkClass:NSObject {
void(^resultHandlerBlock)(NSArray *results); //this block has as param a NSArray, you can change it to whatever you want
}
-(void)setResultHandlerBlock:(void(^)(NSArray *array))handlerBlock;
@implementation YourNetworkClass
-(void)setResultHandlerBlock:(void(^)(NSArray *array))handlerBlock {
resultHandlerBlock = block;
}
-(void)anotherMethodThatDoesNetworkOperationsAndReturnsAnArray {
....
resultHandlerBlock(arrayOfResults);
}
@interface AViewControllerThatUseNetwork: UIViewController {
}
@implementation AViewControllerThatUseNetwork
-(void)initNetworkClass {
YourNetworkClass *networkClass = [[YourNetworkClass alloc] init]; //or other init methods
[networkClass setResultHandlerBlock:^(NSArray *results) {
//do whatever you want with the array
}];
}
. 他のヒント
私は後ろに似たようなものに尋ねました。私はあなたの解決策が見つかると思います。 AFNETWORKINGメソッドへのブロックを渡す?
一般的に、「ログインした場合にBOOLがBOOLを返す場合」からデータを取得する方法を変更する必要があります。ログインできるかどうかを確認した場合は、失敗した場合はAFNetworkingブロック内で何かをしてください。
上記のリンクはあなたの2番目の質問にも答えます。
あなたのメソッドは、AfNetworking成功(または障害)ブロックから実行されるブロック(または2つ)を取ります。このアプローチは、あなたがしようとしているものの非同期性を包含します。この非同期性のため、リターン値をメソッドに追加することはできません。
だから、あなたはあなたの方法を次のように変えるでしょう:
-(void)isLoggedInWithCompletion:(LoginCompletionBlock)completion {
...
[manager GET:urlString parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"JSON: %@", responseObject);
completion(/* whatever parameters your block specifies */);
} ...
}
. だから、状況についての更新(すべての貴重な提案のありがとう。今すぐ私のコードはこのように見えます(私のNetworkModel.mでは、私はInewallyModel.hにメソッドを追加しました。
-(void)isLoggedIn:(void(^)(BOOL isLoggedIn))completionBlock {
NSString *urlString = [NSString stringWithFormat:@"%@%@%@", kBaseURL, kAPI, kUserIsLogged];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer = [AFJSONResponseSerializer serializerWithReadingOptions:NSJSONReadingAllowFragments];
[manager GET:urlString parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"JSON: %@", responseObject);
if ([[NSString stringWithFormat:@"%@", responseObject] isEqualToString:@"true"]) {
completionBlock(YES);
} else {
completionBlock(NO);
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"Error: %@", error);
completionBlock(NO);
}];
}
.
私のappdelegate.h私は私のNetworkModel.hを含めました。
[[self model] isLoggedIn:^(BOOL isLoggedIn) {
if (isLoggedIn == YES) {
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
UIViewController *controller = [storyboard instantiateViewControllerWithIdentifier:@"Start01"];
[self.window setRootViewController:controller];
} else {
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
UIViewController *controller = [storyboard instantiateViewControllerWithIdentifier:@"Start00"];
[self.window setRootViewController:controller];
}
}];
.
とそれはちょっとうまく機能します。しかし今、私はこれについて別の質問があります。私がアプリを実行するとき、何が悪いことがあります。ユーザーログインステータスに関する情報を取得するとすぐに、VC(StoryBoardの指定InitialVoard - Start00)からVC(LoggedInvc - Start01)へのジャンプ。このKIDAがユーザーにジャンプすることを見せないような方法はありますか?またはこれは通常の行動ですか?今、ユーザーは最初の画面を2回目に見え、それから彼が実際に見るべき画面(彼はログインしている)。
しかし、私はブロックを扱う最も簡単な方法を推測し、これはそれらを必要とする場所を正しく使うことです。それらをメソッドやクラスにカプセル化しようとする代わりに、または何でも。データがそこにあるとすぐに、私が成功または失敗ブロックの中に直接持っていることをします。私は正しいことを考えていますか?